]> git.proxmox.com Git - mirror_qemu.git/commitdiff
ui/dbus: add p2p=on/off option
authorMarc-André Lureau <marcandre.lureau@redhat.com>
Sat, 9 Oct 2021 20:16:57 +0000 (00:16 +0400)
committerMarc-André Lureau <marcandre.lureau@redhat.com>
Tue, 21 Dec 2021 06:50:22 +0000 (10:50 +0400)
Add an option to use direct connections instead of via the bus. Clients
are accepted with QMP add_client.

This allows to provide the D-Bus display without a bus. It also
simplifies the testing setup (some CI have issues to setup a D-Bus bus
in a container).

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
13 files changed:
include/qemu/cutils.h
include/ui/dbus-display.h [new file with mode: 0644]
include/ui/dbus-module.h [new file with mode: 0644]
monitor/qmp-cmds.c
qapi/misc.json
qapi/ui.json
qemu-options.hx
ui/dbus-console.c
ui/dbus-listener.c
ui/dbus-module.c [new file with mode: 0644]
ui/dbus.c
ui/dbus.h
ui/meson.build

index 986ed8e15f41248e3802b53cab08c8a939b957d6..320543950c4c2a66a05daee12638b00e61b951ca 100644 (file)
@@ -209,4 +209,9 @@ int qemu_pstrcmp0(const char **str1, const char **str2);
  */
 char *get_relocated_path(const char *dir);
 
+static inline const char *yes_no(bool b)
+{
+     return b ? "yes" : "no";
+}
+
 #endif
diff --git a/include/ui/dbus-display.h b/include/ui/dbus-display.h
new file mode 100644 (file)
index 0000000..88f153c
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef DBUS_DISPLAY_H_
+#define DBUS_DISPLAY_H_
+
+#include "qapi/error.h"
+#include "ui/dbus-module.h"
+
+static inline bool qemu_using_dbus_display(Error **errp)
+{
+    if (!using_dbus_display) {
+        error_set(errp, ERROR_CLASS_DEVICE_NOT_ACTIVE,
+                  "D-Bus display is not in use");
+        return false;
+    }
+    return true;
+}
+
+#endif /* DBUS_DISPLAY_H_ */
diff --git a/include/ui/dbus-module.h b/include/ui/dbus-module.h
new file mode 100644 (file)
index 0000000..ace4a17
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef DBUS_MODULE_H_
+#define DBUS_MODULE_H_
+
+struct QemuDBusDisplayOps {
+    bool (*add_client)(int csock, Error **errp);
+};
+
+extern int using_dbus_display;
+extern struct QemuDBusDisplayOps qemu_dbus_display;
+
+#endif /* DBUS_MODULE_H_*/
index 343353e27a7acaafe661f17a6002144d817a116e..14e3beeaafcf95e424e2e6e3b49d338d41a52889 100644 (file)
@@ -24,6 +24,7 @@
 #include "chardev/char.h"
 #include "ui/qemu-spice.h"
 #include "ui/console.h"
+#include "ui/dbus-display.h"
 #include "sysemu/kvm.h"
 #include "sysemu/runstate.h"
 #include "sysemu/runstate-action.h"
@@ -285,6 +286,18 @@ void qmp_add_client(const char *protocol, const char *fdname,
         skipauth = has_skipauth ? skipauth : false;
         vnc_display_add_client(NULL, fd, skipauth);
         return;
+#endif
+#ifdef CONFIG_DBUS_DISPLAY
+    } else if (strcmp(protocol, "@dbus-display") == 0) {
+        if (!qemu_using_dbus_display(errp)) {
+            close(fd);
+            return;
+        }
+        if (!qemu_dbus_display.add_client(fd, errp)) {
+            close(fd);
+            return;
+        }
+        return;
 #endif
     } else if ((s = qemu_chr_find(protocol)) != NULL) {
         if (qemu_chr_add_client(s, fd) < 0) {
index 358548abe1adc80bbd252c1d38a84fb3c282a92d..e8054f415b21dfee0db06e9183590ab26dae23ba 100644 (file)
@@ -14,8 +14,8 @@
 # Allow client connections for VNC, Spice and socket based
 # character devices to be passed in to QEMU via SCM_RIGHTS.
 #
-# @protocol: protocol name. Valid names are "vnc", "spice" or the
-#            name of a character device (eg. from -chardev id=XXXX)
+# @protocol: protocol name. Valid names are "vnc", "spice", "@dbus-display" or
+#            the name of a character device (eg. from -chardev id=XXXX)
 #
 # @fdname: file descriptor name previously passed via 'getfd' command
 #
index 80855328b1d4b974c75c0c7cad5e78f1cd5be521..d435e94722642ccef4fdffcaa66112aa6a49c412 100644 (file)
 # @rendernode: Which DRM render node should be used. Default is the first
 #              available node on the host.
 #
+# @p2p: Whether to use peer-to-peer connections (accepted through
+#       ``add_client``).
+#
 # Since: 7.0
 #
 ##
 { 'struct'  : 'DisplayDBus',
   'data'    : { '*rendernode' : 'str',
-                '*addr': 'str' } }
+                '*addr': 'str',
+                '*p2p': 'bool' } }
 
  ##
  # @DisplayGLMode:
index 38983a919b12684399fb553b6d01ded06c7e861b..977e0873a12ce0d355a6ae7118f2a8efb85f097b 100644 (file)
@@ -1901,8 +1901,10 @@ SRST
 
         ``addr=<dbusaddr>`` : D-Bus bus address to connect to.
 
-        ``gl=on|off|core|es`` : Use OpenGL for rendering (the D-interface will
-        share framebuffers with DMABUF file descriptors).
+        ``p2p=yes|no`` : Use peer-to-peer connection, accepted via QMP ``add_client``.
+
+        ``gl=on|off|core|es`` : Use OpenGL for rendering (the D-Bus interface
+        will share framebuffers with DMABUF file descriptors).
 
     ``sdl``
         Display video output via SDL (usually in a separate graphics
index 1ccf638c1061e3e73ec06ed2cba90244524938ac..e062f721d761608f3e894cbcddbd9234309625c1 100644 (file)
@@ -219,7 +219,7 @@ dbus_console_register_listener(DBusDisplayConsole *ddc,
     DBusDisplayListener *listener;
     int fd;
 
-    if (g_hash_table_contains(ddc->listeners, sender)) {
+    if (sender && g_hash_table_contains(ddc->listeners, sender)) {
         g_dbus_method_invocation_return_error(
             invocation,
             DBUS_DISPLAY_ERROR,
index 20094fc18abe6d723a85edd3423e67e115a78584..81c119b13a2c528169318d57146806abecfa8d49 100644 (file)
@@ -440,7 +440,7 @@ dbus_display_listener_init(DBusDisplayListener *ddl)
 const char *
 dbus_display_listener_get_bus_name(DBusDisplayListener *ddl)
 {
-    return ddl->bus_name;
+    return ddl->bus_name ?: "p2p";
 }
 
 DBusDisplayConsole *
diff --git a/ui/dbus-module.c b/ui/dbus-module.c
new file mode 100644 (file)
index 0000000..c8771fe
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * D-Bus module support.
+ *
+ * Copyright (C) 2021 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "ui/dbus-module.h"
+
+int using_dbus_display;
+
+static bool
+qemu_dbus_display_add_client(int csock, Error **errp)
+{
+    error_setg(errp, "D-Bus display isn't enabled");
+    return false;
+}
+
+struct QemuDBusDisplayOps qemu_dbus_display = {
+    .add_client = qemu_dbus_display_add_client,
+};
index 12da8ffe31e0b0af4b0c400a6b3ac4f933913e80..847a6678211631de198480522ebf99d8df1205eb 100644 (file)
--- a/ui/dbus.c
+++ b/ui/dbus.c
  * THE SOFTWARE.
  */
 #include "qemu/osdep.h"
+#include "qemu/cutils.h"
 #include "qemu/dbus.h"
 #include "qemu/option.h"
 #include "qom/object_interfaces.h"
 #include "sysemu/sysemu.h"
+#include "ui/dbus-module.h"
 #include "ui/egl-helpers.h"
 #include "ui/egl-context.h"
 #include "qapi/error.h"
@@ -33,6 +35,8 @@
 
 #include "dbus.h"
 
+static DBusDisplay *dbus_display;
+
 static QEMUGLContext dbus_create_context(DisplayGLCtx *dgc,
                                          QEMUGLParams *params)
 {
@@ -73,9 +77,14 @@ dbus_display_finalize(Object *o)
 
     g_clear_object(&dd->server);
     g_clear_pointer(&dd->consoles, g_ptr_array_unref);
+    if (dd->add_client_cancellable) {
+        g_cancellable_cancel(dd->add_client_cancellable);
+    }
+    g_clear_object(&dd->add_client_cancellable);
     g_clear_object(&dd->bus);
     g_clear_object(&dd->iface);
     g_free(dd->dbus_addr);
+    dbus_display = NULL;
 }
 
 static bool
@@ -115,7 +124,10 @@ dbus_display_complete(UserCreatable *uc, Error **errp)
         return;
     }
 
-    if (dd->dbus_addr && *dd->dbus_addr) {
+    if (dd->p2p) {
+        /* wait for dbus_display_add_client() */
+        dbus_display = dd;
+    } else if (dd->dbus_addr && *dd->dbus_addr) {
         dd->bus = g_dbus_connection_new_for_address_sync(dd->dbus_addr,
                         G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
                         G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION,
@@ -151,10 +163,85 @@ dbus_display_complete(UserCreatable *uc, Error **errp)
                  "console-ids", console_ids,
                  NULL);
 
-    g_dbus_object_manager_server_set_connection(dd->server, dd->bus);
-    g_bus_own_name_on_connection(dd->bus, "org.qemu",
-                                 G_BUS_NAME_OWNER_FLAGS_NONE,
-                                 NULL, NULL, NULL, NULL);
+    if (dd->bus) {
+        g_dbus_object_manager_server_set_connection(dd->server, dd->bus);
+        g_bus_own_name_on_connection(dd->bus, "org.qemu",
+                                     G_BUS_NAME_OWNER_FLAGS_NONE,
+                                     NULL, NULL, NULL, NULL);
+    }
+}
+
+static void
+dbus_display_add_client_ready(GObject *source_object,
+                              GAsyncResult *res,
+                              gpointer user_data)
+{
+    g_autoptr(GError) err = NULL;
+    g_autoptr(GDBusConnection) conn = NULL;
+
+    g_clear_object(&dbus_display->add_client_cancellable);
+
+    conn = g_dbus_connection_new_finish(res, &err);
+    if (!conn) {
+        error_printf("Failed to accept D-Bus client: %s", err->message);
+    }
+
+    g_dbus_object_manager_server_set_connection(dbus_display->server, conn);
+}
+
+
+static bool
+dbus_display_add_client(int csock, Error **errp)
+{
+    g_autoptr(GError) err = NULL;
+    g_autoptr(GSocket) socket = NULL;
+    g_autoptr(GSocketConnection) conn = NULL;
+    g_autofree char *guid = g_dbus_generate_guid();
+
+    if (!dbus_display) {
+        error_setg(errp, "p2p connections not accepted in bus mode");
+        return false;
+    }
+
+    if (dbus_display->add_client_cancellable) {
+        g_cancellable_cancel(dbus_display->add_client_cancellable);
+    }
+
+    socket = g_socket_new_from_fd(csock, &err);
+    if (!socket) {
+        error_setg(errp, "Failed to setup D-Bus socket: %s", err->message);
+        return false;
+    }
+
+    conn = g_socket_connection_factory_create_connection(socket);
+
+    dbus_display->add_client_cancellable = g_cancellable_new();
+
+    g_dbus_connection_new(G_IO_STREAM(conn),
+                          guid,
+                          G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER,
+                          NULL,
+                          dbus_display->add_client_cancellable,
+                          dbus_display_add_client_ready,
+                          NULL);
+
+    return true;
+}
+
+static bool
+get_dbus_p2p(Object *o, Error **errp)
+{
+    DBusDisplay *dd = DBUS_DISPLAY(o);
+
+    return dd->p2p;
+}
+
+static void
+set_dbus_p2p(Object *o, bool p2p, Error **errp)
+{
+    DBusDisplay *dd = DBUS_DISPLAY(o);
+
+    dd->p2p = p2p;
 }
 
 static char *
@@ -196,6 +283,7 @@ dbus_display_class_init(ObjectClass *oc, void *data)
     UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
 
     ucc->complete = dbus_display_complete;
+    object_class_property_add_bool(oc, "p2p", get_dbus_p2p, set_dbus_p2p);
     object_class_property_add_str(oc, "addr", get_dbus_addr, set_dbus_addr);
     object_class_property_add_enum(oc, "gl-mode",
                                    "DisplayGLMode", &DisplayGLMode_lookup,
@@ -222,11 +310,19 @@ dbus_init(DisplayState *ds, DisplayOptions *opts)
 {
     DisplayGLMode mode = opts->has_gl ? opts->gl : DISPLAYGL_MODE_OFF;
 
+    if (opts->u.dbus.addr && opts->u.dbus.p2p) {
+        error_report("dbus: can't accept both addr=X and p2p=yes options");
+        exit(1);
+    }
+
+    using_dbus_display = 1;
+
     object_new_with_props(TYPE_DBUS_DISPLAY,
                           object_get_objects_root(),
                           "dbus-display", &error_fatal,
                           "addr", opts->u.dbus.addr ?: "",
                           "gl-mode", DisplayGLMode_str(mode),
+                          "p2p", yes_no(opts->u.dbus.p2p),
                           NULL);
 }
 
@@ -251,6 +347,9 @@ static QemuDisplay qemu_display_dbus = {
 
 static void register_dbus(void)
 {
+    qemu_dbus_display = (struct QemuDBusDisplayOps) {
+        .add_client = dbus_display_add_client,
+    };
     type_register_static(&dbus_display_info);
     qemu_display_register(&qemu_display_dbus);
 }
index d3c9598dd133b242225f4eaa90d6ef8bb0401ca8..4698d324632e796c50961e112d9c8a95af891aa1 100644 (file)
--- a/ui/dbus.h
+++ b/ui/dbus.h
@@ -34,6 +34,7 @@ struct DBusDisplay {
     Object parent;
 
     DisplayGLMode gl_mode;
+    bool p2p;
     char *dbus_addr;
     DisplayGLCtx glctx;
 
@@ -41,6 +42,7 @@ struct DBusDisplay {
     GDBusObjectManagerServer *server;
     QemuDBusDisplay1VM *iface;
     GPtrArray *consoles;
+    GCancellable *add_client_cancellable;
 };
 
 #define TYPE_DBUS_DISPLAY "dbus-display"
index 6270aa768b6a2fc0b65a488bb80e9693f47c313e..80f21704ada6a2d4eeed9af1d63a15e185160068 100644 (file)
@@ -14,6 +14,9 @@ softmmu_ss.add(files(
   'qemu-pixman.c',
   'util.c',
 ))
+if dbus_display
+  softmmu_ss.add(files('dbus-module.c'))
+endif
 softmmu_ss.add([spice_headers, files('spice-module.c')])
 softmmu_ss.add(when: spice_protocol, if_true: files('vdagent.c'))