ui/dbus: add p2p=on/off option
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>
This commit is contained in:
parent
142ca628a7
commit
99997823bb
@ -209,4 +209,9 @@ int qemu_pstrcmp0(const char **str1, const char **str2);
|
|||||||
*/
|
*/
|
||||||
char *get_relocated_path(const char *dir);
|
char *get_relocated_path(const char *dir);
|
||||||
|
|
||||||
|
static inline const char *yes_no(bool b)
|
||||||
|
{
|
||||||
|
return b ? "yes" : "no";
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
17
include/ui/dbus-display.h
Normal file
17
include/ui/dbus-display.h
Normal file
@ -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_ */
|
11
include/ui/dbus-module.h
Normal file
11
include/ui/dbus-module.h
Normal file
@ -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_*/
|
@ -24,6 +24,7 @@
|
|||||||
#include "chardev/char.h"
|
#include "chardev/char.h"
|
||||||
#include "ui/qemu-spice.h"
|
#include "ui/qemu-spice.h"
|
||||||
#include "ui/console.h"
|
#include "ui/console.h"
|
||||||
|
#include "ui/dbus-display.h"
|
||||||
#include "sysemu/kvm.h"
|
#include "sysemu/kvm.h"
|
||||||
#include "sysemu/runstate.h"
|
#include "sysemu/runstate.h"
|
||||||
#include "sysemu/runstate-action.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;
|
skipauth = has_skipauth ? skipauth : false;
|
||||||
vnc_display_add_client(NULL, fd, skipauth);
|
vnc_display_add_client(NULL, fd, skipauth);
|
||||||
return;
|
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
|
#endif
|
||||||
} else if ((s = qemu_chr_find(protocol)) != NULL) {
|
} else if ((s = qemu_chr_find(protocol)) != NULL) {
|
||||||
if (qemu_chr_add_client(s, fd) < 0) {
|
if (qemu_chr_add_client(s, fd) < 0) {
|
||||||
|
@ -14,8 +14,8 @@
|
|||||||
# Allow client connections for VNC, Spice and socket based
|
# Allow client connections for VNC, Spice and socket based
|
||||||
# character devices to be passed in to QEMU via SCM_RIGHTS.
|
# character devices to be passed in to QEMU via SCM_RIGHTS.
|
||||||
#
|
#
|
||||||
# @protocol: protocol name. Valid names are "vnc", "spice" or the
|
# @protocol: protocol name. Valid names are "vnc", "spice", "@dbus-display" or
|
||||||
# name of a character device (eg. from -chardev id=XXXX)
|
# the name of a character device (eg. from -chardev id=XXXX)
|
||||||
#
|
#
|
||||||
# @fdname: file descriptor name previously passed via 'getfd' command
|
# @fdname: file descriptor name previously passed via 'getfd' command
|
||||||
#
|
#
|
||||||
|
@ -1131,12 +1131,16 @@
|
|||||||
# @rendernode: Which DRM render node should be used. Default is the first
|
# @rendernode: Which DRM render node should be used. Default is the first
|
||||||
# available node on the host.
|
# available node on the host.
|
||||||
#
|
#
|
||||||
|
# @p2p: Whether to use peer-to-peer connections (accepted through
|
||||||
|
# ``add_client``).
|
||||||
|
#
|
||||||
# Since: 7.0
|
# Since: 7.0
|
||||||
#
|
#
|
||||||
##
|
##
|
||||||
{ 'struct' : 'DisplayDBus',
|
{ 'struct' : 'DisplayDBus',
|
||||||
'data' : { '*rendernode' : 'str',
|
'data' : { '*rendernode' : 'str',
|
||||||
'*addr': 'str' } }
|
'*addr': 'str',
|
||||||
|
'*p2p': 'bool' } }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @DisplayGLMode:
|
# @DisplayGLMode:
|
||||||
|
@ -1901,8 +1901,10 @@ SRST
|
|||||||
|
|
||||||
``addr=<dbusaddr>`` : D-Bus bus address to connect to.
|
``addr=<dbusaddr>`` : D-Bus bus address to connect to.
|
||||||
|
|
||||||
``gl=on|off|core|es`` : Use OpenGL for rendering (the D-interface will
|
``p2p=yes|no`` : Use peer-to-peer connection, accepted via QMP ``add_client``.
|
||||||
share framebuffers with DMABUF file descriptors).
|
|
||||||
|
``gl=on|off|core|es`` : Use OpenGL for rendering (the D-Bus interface
|
||||||
|
will share framebuffers with DMABUF file descriptors).
|
||||||
|
|
||||||
``sdl``
|
``sdl``
|
||||||
Display video output via SDL (usually in a separate graphics
|
Display video output via SDL (usually in a separate graphics
|
||||||
|
@ -219,7 +219,7 @@ dbus_console_register_listener(DBusDisplayConsole *ddc,
|
|||||||
DBusDisplayListener *listener;
|
DBusDisplayListener *listener;
|
||||||
int fd;
|
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(
|
g_dbus_method_invocation_return_error(
|
||||||
invocation,
|
invocation,
|
||||||
DBUS_DISPLAY_ERROR,
|
DBUS_DISPLAY_ERROR,
|
||||||
|
@ -440,7 +440,7 @@ dbus_display_listener_init(DBusDisplayListener *ddl)
|
|||||||
const char *
|
const char *
|
||||||
dbus_display_listener_get_bus_name(DBusDisplayListener *ddl)
|
dbus_display_listener_get_bus_name(DBusDisplayListener *ddl)
|
||||||
{
|
{
|
||||||
return ddl->bus_name;
|
return ddl->bus_name ?: "p2p";
|
||||||
}
|
}
|
||||||
|
|
||||||
DBusDisplayConsole *
|
DBusDisplayConsole *
|
||||||
|
35
ui/dbus-module.c
Normal file
35
ui/dbus-module.c
Normal file
@ -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,
|
||||||
|
};
|
109
ui/dbus.c
109
ui/dbus.c
@ -22,10 +22,12 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
|
#include "qemu/cutils.h"
|
||||||
#include "qemu/dbus.h"
|
#include "qemu/dbus.h"
|
||||||
#include "qemu/option.h"
|
#include "qemu/option.h"
|
||||||
#include "qom/object_interfaces.h"
|
#include "qom/object_interfaces.h"
|
||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
|
#include "ui/dbus-module.h"
|
||||||
#include "ui/egl-helpers.h"
|
#include "ui/egl-helpers.h"
|
||||||
#include "ui/egl-context.h"
|
#include "ui/egl-context.h"
|
||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
@ -33,6 +35,8 @@
|
|||||||
|
|
||||||
#include "dbus.h"
|
#include "dbus.h"
|
||||||
|
|
||||||
|
static DBusDisplay *dbus_display;
|
||||||
|
|
||||||
static QEMUGLContext dbus_create_context(DisplayGLCtx *dgc,
|
static QEMUGLContext dbus_create_context(DisplayGLCtx *dgc,
|
||||||
QEMUGLParams *params)
|
QEMUGLParams *params)
|
||||||
{
|
{
|
||||||
@ -73,9 +77,14 @@ dbus_display_finalize(Object *o)
|
|||||||
|
|
||||||
g_clear_object(&dd->server);
|
g_clear_object(&dd->server);
|
||||||
g_clear_pointer(&dd->consoles, g_ptr_array_unref);
|
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->bus);
|
||||||
g_clear_object(&dd->iface);
|
g_clear_object(&dd->iface);
|
||||||
g_free(dd->dbus_addr);
|
g_free(dd->dbus_addr);
|
||||||
|
dbus_display = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
@ -115,7 +124,10 @@ dbus_display_complete(UserCreatable *uc, Error **errp)
|
|||||||
return;
|
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,
|
dd->bus = g_dbus_connection_new_for_address_sync(dd->dbus_addr,
|
||||||
G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
|
G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
|
||||||
G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION,
|
G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION,
|
||||||
@ -151,10 +163,85 @@ dbus_display_complete(UserCreatable *uc, Error **errp)
|
|||||||
"console-ids", console_ids,
|
"console-ids", console_ids,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
g_dbus_object_manager_server_set_connection(dd->server, dd->bus);
|
if (dd->bus) {
|
||||||
g_bus_own_name_on_connection(dd->bus, "org.qemu",
|
g_dbus_object_manager_server_set_connection(dd->server, dd->bus);
|
||||||
G_BUS_NAME_OWNER_FLAGS_NONE,
|
g_bus_own_name_on_connection(dd->bus, "org.qemu",
|
||||||
NULL, NULL, NULL, NULL);
|
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 *
|
static char *
|
||||||
@ -196,6 +283,7 @@ dbus_display_class_init(ObjectClass *oc, void *data)
|
|||||||
UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
|
UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
|
||||||
|
|
||||||
ucc->complete = dbus_display_complete;
|
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_str(oc, "addr", get_dbus_addr, set_dbus_addr);
|
||||||
object_class_property_add_enum(oc, "gl-mode",
|
object_class_property_add_enum(oc, "gl-mode",
|
||||||
"DisplayGLMode", &DisplayGLMode_lookup,
|
"DisplayGLMode", &DisplayGLMode_lookup,
|
||||||
@ -222,11 +310,19 @@ dbus_init(DisplayState *ds, DisplayOptions *opts)
|
|||||||
{
|
{
|
||||||
DisplayGLMode mode = opts->has_gl ? opts->gl : DISPLAYGL_MODE_OFF;
|
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_new_with_props(TYPE_DBUS_DISPLAY,
|
||||||
object_get_objects_root(),
|
object_get_objects_root(),
|
||||||
"dbus-display", &error_fatal,
|
"dbus-display", &error_fatal,
|
||||||
"addr", opts->u.dbus.addr ?: "",
|
"addr", opts->u.dbus.addr ?: "",
|
||||||
"gl-mode", DisplayGLMode_str(mode),
|
"gl-mode", DisplayGLMode_str(mode),
|
||||||
|
"p2p", yes_no(opts->u.dbus.p2p),
|
||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,6 +347,9 @@ static QemuDisplay qemu_display_dbus = {
|
|||||||
|
|
||||||
static void register_dbus(void)
|
static void register_dbus(void)
|
||||||
{
|
{
|
||||||
|
qemu_dbus_display = (struct QemuDBusDisplayOps) {
|
||||||
|
.add_client = dbus_display_add_client,
|
||||||
|
};
|
||||||
type_register_static(&dbus_display_info);
|
type_register_static(&dbus_display_info);
|
||||||
qemu_display_register(&qemu_display_dbus);
|
qemu_display_register(&qemu_display_dbus);
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@ struct DBusDisplay {
|
|||||||
Object parent;
|
Object parent;
|
||||||
|
|
||||||
DisplayGLMode gl_mode;
|
DisplayGLMode gl_mode;
|
||||||
|
bool p2p;
|
||||||
char *dbus_addr;
|
char *dbus_addr;
|
||||||
DisplayGLCtx glctx;
|
DisplayGLCtx glctx;
|
||||||
|
|
||||||
@ -41,6 +42,7 @@ struct DBusDisplay {
|
|||||||
GDBusObjectManagerServer *server;
|
GDBusObjectManagerServer *server;
|
||||||
QemuDBusDisplay1VM *iface;
|
QemuDBusDisplay1VM *iface;
|
||||||
GPtrArray *consoles;
|
GPtrArray *consoles;
|
||||||
|
GCancellable *add_client_cancellable;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define TYPE_DBUS_DISPLAY "dbus-display"
|
#define TYPE_DBUS_DISPLAY "dbus-display"
|
||||||
|
@ -14,6 +14,9 @@ softmmu_ss.add(files(
|
|||||||
'qemu-pixman.c',
|
'qemu-pixman.c',
|
||||||
'util.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([spice_headers, files('spice-module.c')])
|
||||||
softmmu_ss.add(when: spice_protocol, if_true: files('vdagent.c'))
|
softmmu_ss.add(when: spice_protocol, if_true: files('vdagent.c'))
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user