[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 05/21] ui/dbus: win32 support
From: |
marcandre . lureau |
Subject: |
[PATCH 05/21] ui/dbus: win32 support |
Date: |
Tue, 6 Jun 2023 15:56:42 +0400 |
From: Marc-André Lureau <marcandre.lureau@redhat.com>
D-Bus doesn't support fd-passing on Windows (AF_UNIX doesn't have
SCM_RIGHTS yet, but there are other means to share objects. I have
proposed various solutions upstream, but none seem fitting enough atm).
To make the "-display dbus" work on Windows, implement an alternative
D-Bus interface where all the 'h' (FDs) arguments are replaced with
'ay' (WSASocketW data), and sockets are passed to the other end via
WSADuplicateSocket().
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
meson.build | 4 +--
ui/dbus.h | 6 +++++
audio/dbusaudio.c | 44 +++++++++++++++++++++++++++------
ui/dbus-chardev.c | 22 +++++++++++++----
ui/dbus-console.c | 59 ++++++++++++++++++++++++++++++++++++++------
ui/dbus-display1.xml | 28 +++++++++++++++++++++
ui/meson.build | 9 ++++++-
7 files changed, 149 insertions(+), 23 deletions(-)
diff --git a/meson.build b/meson.build
index a61d3e9b06..ce7138a69f 100644
--- a/meson.build
+++ b/meson.build
@@ -838,6 +838,8 @@ if gdbus_codegen.found() and get_option('cfi')
gdbus_codegen_error = '@0@ uses gdbus-codegen, which does not support
control flow integrity'
endif
+xml_pp = find_program('scripts/xml-preprocess.py')
+
lttng = not_found
if 'ust' in get_option('trace_backends')
lttng = dependency('lttng-ust', required: true, version: '>= 2.1',
@@ -2008,8 +2010,6 @@ dbus_display = get_option('dbus_display') \
error_message: '-display dbus requires glib>=2.64') \
.require(gdbus_codegen.found(),
error_message: gdbus_codegen_error.format('-display dbus')) \
- .require(targetos != 'windows',
- error_message: '-display dbus is not available on Windows') \
.allowed()
have_virtfs = get_option('virtfs') \
diff --git a/ui/dbus.h b/ui/dbus.h
index 9c149e7b41..1e8c24a48e 100644
--- a/ui/dbus.h
+++ b/ui/dbus.h
@@ -62,6 +62,12 @@ struct DBusDisplay {
Notifier notifier;
};
+#ifdef WIN32
+bool
+dbus_win32_import_socket(GDBusMethodInvocation *invocation,
+ GVariant *arg_listener, int *socket);
+#endif
+
#define TYPE_DBUS_DISPLAY "dbus-display"
OBJECT_DECLARE_SIMPLE_TYPE(DBusDisplay, DBUS_DISPLAY)
diff --git a/audio/dbusaudio.c b/audio/dbusaudio.c
index de59467d9e..7a11fbfb42 100644
--- a/audio/dbusaudio.c
+++ b/audio/dbusaudio.c
@@ -33,6 +33,7 @@
#include <gio/gunixfdlist.h>
#endif
+#include "ui/dbus.h"
#include "ui/dbus-display1.h"
#define AUDIO_CAP "dbus"
@@ -422,7 +423,6 @@ dbus_audio_fini(void *opaque)
g_free(da);
}
-#ifdef G_OS_UNIX
static void
listener_out_vanished_cb(GDBusConnection *connection,
gboolean remote_peer_vanished,
@@ -448,7 +448,9 @@ listener_in_vanished_cb(GDBusConnection *connection,
static gboolean
dbus_audio_register_listener(AudioState *s,
GDBusMethodInvocation *invocation,
+#ifdef G_OS_UNIX
GUnixFDList *fd_list,
+#endif
GVariant *arg_listener,
bool out)
{
@@ -475,6 +477,11 @@ dbus_audio_register_listener(AudioState *s,
return DBUS_METHOD_INVOCATION_HANDLED;
}
+#ifdef G_OS_WIN32
+ if (!dbus_win32_import_socket(invocation, arg_listener, &fd)) {
+ return DBUS_METHOD_INVOCATION_HANDLED;
+ }
+#else
fd = g_unix_fd_list_get(fd_list, g_variant_get_handle(arg_listener), &err);
if (err) {
g_dbus_method_invocation_return_error(invocation,
@@ -484,6 +491,7 @@ dbus_audio_register_listener(AudioState *s,
err->message);
return DBUS_METHOD_INVOCATION_HANDLED;
}
+#endif
socket = g_socket_new_from_fd(fd, &err);
if (err) {
@@ -492,15 +500,28 @@ dbus_audio_register_listener(AudioState *s,
DBUS_DISPLAY_ERROR_FAILED,
"Couldn't make a socket: %s",
err->message);
+#ifdef G_OS_WIN32
+ closesocket(fd);
+#else
+ close(fd);
+#endif
return DBUS_METHOD_INVOCATION_HANDLED;
}
socket_conn = g_socket_connection_factory_create_connection(socket);
if (out) {
qemu_dbus_display1_audio_complete_register_out_listener(
- da->iface, invocation, NULL);
+ da->iface, invocation
+#ifdef G_OS_UNIX
+ , NULL
+#endif
+ );
} else {
qemu_dbus_display1_audio_complete_register_in_listener(
- da->iface, invocation, NULL);
+ da->iface, invocation
+#ifdef G_OS_UNIX
+ , NULL
+#endif
+ );
}
listener_conn =
@@ -578,24 +599,33 @@ dbus_audio_register_listener(AudioState *s,
static gboolean
dbus_audio_register_out_listener(AudioState *s,
GDBusMethodInvocation *invocation,
+#ifdef G_OS_UNIX
GUnixFDList *fd_list,
+#endif
GVariant *arg_listener)
{
return dbus_audio_register_listener(s, invocation,
- fd_list, arg_listener, true);
+#ifdef G_OS_UNIX
+ fd_list,
+#endif
+ arg_listener, true);
}
static gboolean
dbus_audio_register_in_listener(AudioState *s,
GDBusMethodInvocation *invocation,
+#ifdef G_OS_UNIX
GUnixFDList *fd_list,
+#endif
GVariant *arg_listener)
{
return dbus_audio_register_listener(s, invocation,
- fd_list, arg_listener, false);
-}
+#ifdef G_OS_UNIX
+ fd_list,
#endif
+ arg_listener, false);
+}
static void
dbus_audio_set_server(AudioState *s, GDBusObjectManagerServer *server, bool
p2p)
@@ -610,14 +640,12 @@ dbus_audio_set_server(AudioState *s,
GDBusObjectManagerServer *server, bool p2p)
da->audio = g_dbus_object_skeleton_new(DBUS_DISPLAY1_AUDIO_PATH);
da->iface = qemu_dbus_display1_audio_skeleton_new();
-#ifdef G_OS_UNIX
g_object_connect(da->iface,
"swapped-signal::handle-register-in-listener",
dbus_audio_register_in_listener, s,
"swapped-signal::handle-register-out-listener",
dbus_audio_register_out_listener, s,
NULL);
-#endif
g_dbus_object_skeleton_add_interface(G_DBUS_OBJECT_SKELETON(da->audio),
G_DBUS_INTERFACE_SKELETON(da->iface));
diff --git a/ui/dbus-chardev.c b/ui/dbus-chardev.c
index 7154d81a9a..1d3a7122a1 100644
--- a/ui/dbus-chardev.c
+++ b/ui/dbus-chardev.c
@@ -110,18 +110,24 @@ dbus_chardev_init(DBusDisplay *dpy)
dbus_display_chardev_foreach, dpy);
}
-#ifdef G_OS_UNIX
static gboolean
dbus_chr_register(
DBusChardev *dc,
GDBusMethodInvocation *invocation,
+#ifdef G_OS_UNIX
GUnixFDList *fd_list,
+#endif
GVariant *arg_stream,
QemuDBusDisplay1Chardev *object)
{
g_autoptr(GError) err = NULL;
int fd;
+#ifdef G_OS_WIN32
+ if (!dbus_win32_import_socket(invocation, arg_stream, &fd)) {
+ return DBUS_METHOD_INVOCATION_HANDLED;
+ }
+#else
fd = g_unix_fd_list_get(fd_list, g_variant_get_handle(arg_stream), &err);
if (err) {
g_dbus_method_invocation_return_error(
@@ -131,13 +137,18 @@ dbus_chr_register(
"Couldn't get peer FD: %s", err->message);
return DBUS_METHOD_INVOCATION_HANDLED;
}
+#endif
if (qemu_chr_add_client(CHARDEV(dc), fd) < 0) {
g_dbus_method_invocation_return_error(invocation,
DBUS_DISPLAY_ERROR,
DBUS_DISPLAY_ERROR_FAILED,
"Couldn't register FD!");
+#ifdef G_OS_WIN32
+ closesocket(fd);
+#else
close(fd);
+#endif
return DBUS_METHOD_INVOCATION_HANDLED;
}
@@ -145,10 +156,13 @@ dbus_chr_register(
"owner", g_dbus_method_invocation_get_sender(invocation),
NULL);
- qemu_dbus_display1_chardev_complete_register(object, invocation, NULL);
+ qemu_dbus_display1_chardev_complete_register(object, invocation
+#ifndef G_OS_WIN32
+ , NULL
+#endif
+ );
return DBUS_METHOD_INVOCATION_HANDLED;
}
-#endif
static gboolean
dbus_chr_send_break(
@@ -179,10 +193,8 @@ dbus_chr_open(Chardev *chr, ChardevBackend *backend,
dc->iface = qemu_dbus_display1_chardev_skeleton_new();
g_object_set(dc->iface, "name", backend->u.dbus.data->name, NULL);
g_object_connect(dc->iface,
-#ifdef G_OS_UNIX
"swapped-signal::handle-register",
dbus_chr_register, dc,
-#endif
"swapped-signal::handle-send-break",
dbus_chr_send_break, dc,
NULL);
diff --git a/ui/dbus-console.c b/ui/dbus-console.c
index fd50fd3200..f0a060dc81 100644
--- a/ui/dbus-console.c
+++ b/ui/dbus-console.c
@@ -162,7 +162,6 @@ dbus_display_console_class_init(DBusDisplayConsoleClass
*klass)
gobject_class->dispose = dbus_display_console_dispose;
}
-#ifdef G_OS_UNIX
static void
listener_vanished_cb(DBusDisplayListener *listener)
{
@@ -174,7 +173,6 @@ listener_vanished_cb(DBusDisplayListener *listener)
g_hash_table_remove(ddc->listeners, name);
qkbd_state_lift_all_keys(ddc->kbd);
}
-#endif
static gboolean
dbus_console_set_ui_info(DBusDisplayConsole *ddc,
@@ -208,11 +206,47 @@ dbus_console_set_ui_info(DBusDisplayConsole *ddc,
return DBUS_METHOD_INVOCATION_HANDLED;
}
-#ifdef G_OS_UNIX
+#ifdef G_OS_WIN32
+bool
+dbus_win32_import_socket(GDBusMethodInvocation *invocation,
+ GVariant *arg_listener, int *socket)
+{
+ gsize n;
+ WSAPROTOCOL_INFOW *info = (void *)g_variant_get_fixed_array(arg_listener,
&n, 1);
+
+ if (!info || n != sizeof(*info)) {
+ g_dbus_method_invocation_return_error(
+ invocation,
+ DBUS_DISPLAY_ERROR,
+ DBUS_DISPLAY_ERROR_FAILED,
+ "Failed to get socket infos");
+ return false;
+ }
+
+ *socket = WSASocketW(FROM_PROTOCOL_INFO,
+ FROM_PROTOCOL_INFO,
+ FROM_PROTOCOL_INFO,
+ info, 0, 0);
+ if (*socket == INVALID_SOCKET) {
+ g_autofree gchar *emsg = g_win32_error_message(WSAGetLastError());
+ g_dbus_method_invocation_return_error(
+ invocation,
+ DBUS_DISPLAY_ERROR,
+ DBUS_DISPLAY_ERROR_FAILED,
+ "Couldn't create socket: %s", emsg);
+ return false;
+ }
+
+ return true;
+}
+#endif
+
static gboolean
dbus_console_register_listener(DBusDisplayConsole *ddc,
GDBusMethodInvocation *invocation,
+#ifdef G_OS_UNIX
GUnixFDList *fd_list,
+#endif
GVariant *arg_listener)
{
const char *sender = g_dbus_method_invocation_get_sender(invocation);
@@ -234,6 +268,11 @@ dbus_console_register_listener(DBusDisplayConsole *ddc,
return DBUS_METHOD_INVOCATION_HANDLED;
}
+#ifdef G_OS_WIN32
+ if (!dbus_win32_import_socket(invocation, arg_listener, &fd)) {
+ return DBUS_METHOD_INVOCATION_HANDLED;
+ }
+#else
fd = g_unix_fd_list_get(fd_list, g_variant_get_handle(arg_listener), &err);
if (err) {
g_dbus_method_invocation_return_error(
@@ -243,6 +282,7 @@ dbus_console_register_listener(DBusDisplayConsole *ddc,
"Couldn't get peer fd: %s", err->message);
return DBUS_METHOD_INVOCATION_HANDLED;
}
+#endif
socket = g_socket_new_from_fd(fd, &err);
if (err) {
@@ -251,13 +291,21 @@ dbus_console_register_listener(DBusDisplayConsole *ddc,
DBUS_DISPLAY_ERROR,
DBUS_DISPLAY_ERROR_FAILED,
"Couldn't make a socket: %s", err->message);
+#ifdef G_OS_WIN32
+ closesocket(fd);
+#else
close(fd);
+#endif
return DBUS_METHOD_INVOCATION_HANDLED;
}
socket_conn = g_socket_connection_factory_create_connection(socket);
qemu_dbus_display1_console_complete_register_listener(
- ddc->iface, invocation, NULL);
+ ddc->iface, invocation
+#ifdef G_OS_UNIX
+ , NULL
+#endif
+ );
listener_conn = g_dbus_connection_new_sync(
G_IO_STREAM(socket_conn),
@@ -284,7 +332,6 @@ dbus_console_register_listener(DBusDisplayConsole *ddc,
trace_dbus_registered_listener(sender);
return DBUS_METHOD_INVOCATION_HANDLED;
}
-#endif
static gboolean
dbus_kbd_press(DBusDisplayConsole *ddc,
@@ -473,10 +520,8 @@ dbus_display_console_new(DBusDisplay *display, QemuConsole
*con)
"device-address", device_addr,
NULL);
g_object_connect(ddc->iface,
-#ifdef G_OS_UNIX
"swapped-signal::handle-register-listener",
dbus_console_register_listener, ddc,
-#endif
"swapped-signal::handle-set-uiinfo",
dbus_console_set_ui_info, ddc,
NULL);
diff --git a/ui/dbus-display1.xml b/ui/dbus-display1.xml
index c3b2293376..80eae363f0 100644
--- a/ui/dbus-display1.xml
+++ b/ui/dbus-display1.xml
@@ -56,7 +56,13 @@
:dbus:iface:`org.qemu.Display1.Listener` interface.
-->
<method name="RegisterListener">
+ <?if $(env.TARGETOS) == windows?>
+ <arg type="ay" name="listener" direction="in">
+ <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+ </arg>
+ <?else?>
<arg type="h" name="listener" direction="in"/>
+ <?endif?>
</method>
<!--
@@ -293,6 +299,9 @@
</arg>
</method>
+ <?if $(env.TARGETOS) == windows?>
+ <!-- Add shared memory/texture support -->
+ <?else?>
<!--
ScanoutDMABUF:
@dmabuf: the DMABUF file descriptor.
@@ -331,6 +340,7 @@
<arg type="i" name="width" direction="in"/>
<arg type="i" name="height" direction="in"/>
</method>
+ <?endif?>
<!--
Disable:
@@ -491,7 +501,13 @@
:dbus:iface:`org.qemu.Display1.AudioOutListener` interface.
-->
<method name="RegisterOutListener">
+ <?if $(env.TARGETOS) == windows?>
+ <arg type="ay" name="listener" direction="in">
+ <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+ </arg>
+ <?else?>
<arg type="h" name="listener" direction="in"/>
+ <?endif?>
</method>
<!--
@@ -506,7 +522,13 @@
:dbus:iface:`org.qemu.Display1.AudioInListener` interface.
-->
<method name="RegisterInListener">
+ <?if $(env.TARGETOS) == windows?>
+ <arg type="ay" name="listener" direction="in">
+ <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+ </arg>
+ <?else?>
<arg type="h" name="listener" direction="in"/>
+ <?endif?>
</method>
</interface>
@@ -719,7 +741,13 @@
The current handler, if any, will be replaced.
-->
<method name="Register">
+ <?if $(env.TARGETOS) == windows?>
+ <arg type="ay" name="listener" direction="in">
+ <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+ </arg>
+ <?else?>
<arg type="h" name="stream" direction="in"/>
+ <?endif?>
</method>
<!--
diff --git a/ui/meson.build b/ui/meson.build
index e09b616a66..d0dd65880c 100644
--- a/ui/meson.build
+++ b/ui/meson.build
@@ -74,9 +74,16 @@ endif
if dbus_display
dbus_ss = ss.source_set()
+ env = environment()
+ env.set('TARGETOS', targetos)
+ xml = custom_target('dbus-display preprocess',
+ input: 'dbus-display1.xml',
+ output: 'dbus-display1.xml',
+ env: env,
+ command: [xml_pp, '@INPUT@', '@OUTPUT@'])
dbus_display1 = custom_target('dbus-display gdbus-codegen',
output: ['dbus-display1.h', 'dbus-display1.c'],
- input: files('dbus-display1.xml'),
+ input: xml,
command: [gdbus_codegen, '@INPUT@',
'--glib-min-required', '2.64',
'--output-directory',
meson.current_build_dir(),
--
2.40.1
- [PATCH 00/21] -display dbus: add win32 support, marcandre . lureau, 2023/06/06
- [PATCH 01/21] ui/egl: export qemu_egl_get_error_string(), marcandre . lureau, 2023/06/06
- [PATCH 02/21] ui/egl: fix make_context_current() callback return value, marcandre . lureau, 2023/06/06
- [PATCH 03/21] ui/dbus: compile without gio/gunixfdlist.h, marcandre . lureau, 2023/06/06
- [PATCH 04/21] scripts: add a XML preprocessor script, marcandre . lureau, 2023/06/06
- [PATCH 05/21] ui/dbus: win32 support,
marcandre . lureau <=
- [PATCH 06/21] qtest: add qtest_pid(), marcandre . lureau, 2023/06/06
- [PATCH 07/21] tests: make dbus-display-test work on win32, marcandre . lureau, 2023/06/06
- [PATCH 08/21] ui/dbus: introduce "Interfaces" properties, marcandre . lureau, 2023/06/06
- [PATCH 10/21] virtio-gpu/win32: allocate shareable 2d resources/images, marcandre . lureau, 2023/06/06
- [PATCH 11/21] ui/dbus: use shared memory when possible on win32, marcandre . lureau, 2023/06/06
- [PATCH 12/21] ui: add egl-headless support on win32, marcandre . lureau, 2023/06/06
- [PATCH 13/21] ui/egl: default to GLES on windows, marcandre . lureau, 2023/06/06
- [PATCH 14/21] ui: add egl_fb_read_rect(), marcandre . lureau, 2023/06/06