Skip to content

Commit

Permalink
ui/dbus: add p2p=on/off option
Browse files Browse the repository at this point in the history
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 <[email protected]>
Acked-by: Gerd Hoffmann <[email protected]>
  • Loading branch information
elmarco committed Dec 21, 2021
1 parent 142ca62 commit 9999782
Show file tree
Hide file tree
Showing 13 changed files with 203 additions and 12 deletions.
5 changes: 5 additions & 0 deletions include/qemu/cutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
17 changes: 17 additions & 0 deletions include/ui/dbus-display.h
Original file line number Diff line number Diff line change
@@ -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 changes: 11 additions & 0 deletions include/ui/dbus-module.h
Original file line number Diff line number Diff line change
@@ -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_*/
13 changes: 13 additions & 0 deletions monitor/qmp-cmds.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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) {
Expand Down
4 changes: 2 additions & 2 deletions qapi/misc.json
Original file line number Diff line number Diff line change
Expand Up @@ -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
#
Expand Down
6 changes: 5 additions & 1 deletion qapi/ui.json
Original file line number Diff line number Diff line change
Expand Up @@ -1131,12 +1131,16 @@
# @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:
Expand Down
6 changes: 4 additions & 2 deletions qemu-options.hx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion ui/dbus-console.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion ui/dbus-listener.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 *
Expand Down
35 changes: 35 additions & 0 deletions ui/dbus-module.c
Original file line number Diff line number Diff line change
@@ -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 changes: 104 additions & 5 deletions ui/dbus.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,21 @@
* 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"
#include "trace.h"

#include "dbus.h"

static DBusDisplay *dbus_display;

static QEMUGLContext dbus_create_context(DisplayGLCtx *dgc,
QEMUGLParams *params)
{
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 *
Expand Down Expand Up @@ -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,
Expand All @@ -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);
}

Expand All @@ -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);
}
Expand Down
2 changes: 2 additions & 0 deletions ui/dbus.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,15 @@ struct DBusDisplay {
Object parent;

DisplayGLMode gl_mode;
bool p2p;
char *dbus_addr;
DisplayGLCtx glctx;

GDBusConnection *bus;
GDBusObjectManagerServer *server;
QemuDBusDisplay1VM *iface;
GPtrArray *consoles;
GCancellable *add_client_cancellable;
};

#define TYPE_DBUS_DISPLAY "dbus-display"
Expand Down
3 changes: 3 additions & 0 deletions ui/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -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'))

Expand Down

0 comments on commit 9999782

Please sign in to comment.