Skip to content

Commit 6cc5a61

Browse files
committed
ui/dbus: win32 support
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 <[email protected]> Message-Id: <[email protected]>
1 parent 9b286e7 commit 6cc5a61

File tree

7 files changed

+149
-23
lines changed

7 files changed

+149
-23
lines changed

audio/dbusaudio.c

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <gio/gunixfdlist.h>
3434
#endif
3535

36+
#include "ui/dbus.h"
3637
#include "ui/dbus-display1.h"
3738

3839
#define AUDIO_CAP "dbus"
@@ -422,7 +423,6 @@ dbus_audio_fini(void *opaque)
422423
g_free(da);
423424
}
424425

425-
#ifdef G_OS_UNIX
426426
static void
427427
listener_out_vanished_cb(GDBusConnection *connection,
428428
gboolean remote_peer_vanished,
@@ -448,7 +448,9 @@ listener_in_vanished_cb(GDBusConnection *connection,
448448
static gboolean
449449
dbus_audio_register_listener(AudioState *s,
450450
GDBusMethodInvocation *invocation,
451+
#ifdef G_OS_UNIX
451452
GUnixFDList *fd_list,
453+
#endif
452454
GVariant *arg_listener,
453455
bool out)
454456
{
@@ -475,6 +477,11 @@ dbus_audio_register_listener(AudioState *s,
475477
return DBUS_METHOD_INVOCATION_HANDLED;
476478
}
477479

480+
#ifdef G_OS_WIN32
481+
if (!dbus_win32_import_socket(invocation, arg_listener, &fd)) {
482+
return DBUS_METHOD_INVOCATION_HANDLED;
483+
}
484+
#else
478485
fd = g_unix_fd_list_get(fd_list, g_variant_get_handle(arg_listener), &err);
479486
if (err) {
480487
g_dbus_method_invocation_return_error(invocation,
@@ -484,6 +491,7 @@ dbus_audio_register_listener(AudioState *s,
484491
err->message);
485492
return DBUS_METHOD_INVOCATION_HANDLED;
486493
}
494+
#endif
487495

488496
socket = g_socket_new_from_fd(fd, &err);
489497
if (err) {
@@ -492,15 +500,28 @@ dbus_audio_register_listener(AudioState *s,
492500
DBUS_DISPLAY_ERROR_FAILED,
493501
"Couldn't make a socket: %s",
494502
err->message);
503+
#ifdef G_OS_WIN32
504+
closesocket(fd);
505+
#else
506+
close(fd);
507+
#endif
495508
return DBUS_METHOD_INVOCATION_HANDLED;
496509
}
497510
socket_conn = g_socket_connection_factory_create_connection(socket);
498511
if (out) {
499512
qemu_dbus_display1_audio_complete_register_out_listener(
500-
da->iface, invocation, NULL);
513+
da->iface, invocation
514+
#ifdef G_OS_UNIX
515+
, NULL
516+
#endif
517+
);
501518
} else {
502519
qemu_dbus_display1_audio_complete_register_in_listener(
503-
da->iface, invocation, NULL);
520+
da->iface, invocation
521+
#ifdef G_OS_UNIX
522+
, NULL
523+
#endif
524+
);
504525
}
505526

506527
listener_conn =
@@ -578,24 +599,33 @@ dbus_audio_register_listener(AudioState *s,
578599
static gboolean
579600
dbus_audio_register_out_listener(AudioState *s,
580601
GDBusMethodInvocation *invocation,
602+
#ifdef G_OS_UNIX
581603
GUnixFDList *fd_list,
604+
#endif
582605
GVariant *arg_listener)
583606
{
584607
return dbus_audio_register_listener(s, invocation,
585-
fd_list, arg_listener, true);
608+
#ifdef G_OS_UNIX
609+
fd_list,
610+
#endif
611+
arg_listener, true);
586612

587613
}
588614

589615
static gboolean
590616
dbus_audio_register_in_listener(AudioState *s,
591617
GDBusMethodInvocation *invocation,
618+
#ifdef G_OS_UNIX
592619
GUnixFDList *fd_list,
620+
#endif
593621
GVariant *arg_listener)
594622
{
595623
return dbus_audio_register_listener(s, invocation,
596-
fd_list, arg_listener, false);
597-
}
624+
#ifdef G_OS_UNIX
625+
fd_list,
598626
#endif
627+
arg_listener, false);
628+
}
599629

600630
static void
601631
dbus_audio_set_server(AudioState *s, GDBusObjectManagerServer *server, bool p2p)
@@ -610,14 +640,12 @@ dbus_audio_set_server(AudioState *s, GDBusObjectManagerServer *server, bool p2p)
610640

611641
da->audio = g_dbus_object_skeleton_new(DBUS_DISPLAY1_AUDIO_PATH);
612642
da->iface = qemu_dbus_display1_audio_skeleton_new();
613-
#ifdef G_OS_UNIX
614643
g_object_connect(da->iface,
615644
"swapped-signal::handle-register-in-listener",
616645
dbus_audio_register_in_listener, s,
617646
"swapped-signal::handle-register-out-listener",
618647
dbus_audio_register_out_listener, s,
619648
NULL);
620-
#endif
621649

622650
g_dbus_object_skeleton_add_interface(G_DBUS_OBJECT_SKELETON(da->audio),
623651
G_DBUS_INTERFACE_SKELETON(da->iface));

meson.build

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,8 @@ if gdbus_codegen.found() and get_option('cfi')
838838
gdbus_codegen_error = '@0@ uses gdbus-codegen, which does not support control flow integrity'
839839
endif
840840

841+
xml_pp = find_program('scripts/xml-preprocess.py')
842+
841843
lttng = not_found
842844
if 'ust' in get_option('trace_backends')
843845
lttng = dependency('lttng-ust', required: true, version: '>= 2.1',
@@ -1985,8 +1987,6 @@ dbus_display = get_option('dbus_display') \
19851987
error_message: '-display dbus requires glib>=2.64') \
19861988
.require(gdbus_codegen.found(),
19871989
error_message: gdbus_codegen_error.format('-display dbus')) \
1988-
.require(targetos != 'windows',
1989-
error_message: '-display dbus is not available on Windows') \
19901990
.allowed()
19911991

19921992
have_virtfs = get_option('virtfs') \

ui/dbus-chardev.c

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,18 +110,24 @@ dbus_chardev_init(DBusDisplay *dpy)
110110
dbus_display_chardev_foreach, dpy);
111111
}
112112

113-
#ifdef G_OS_UNIX
114113
static gboolean
115114
dbus_chr_register(
116115
DBusChardev *dc,
117116
GDBusMethodInvocation *invocation,
117+
#ifdef G_OS_UNIX
118118
GUnixFDList *fd_list,
119+
#endif
119120
GVariant *arg_stream,
120121
QemuDBusDisplay1Chardev *object)
121122
{
122123
g_autoptr(GError) err = NULL;
123124
int fd;
124125

126+
#ifdef G_OS_WIN32
127+
if (!dbus_win32_import_socket(invocation, arg_stream, &fd)) {
128+
return DBUS_METHOD_INVOCATION_HANDLED;
129+
}
130+
#else
125131
fd = g_unix_fd_list_get(fd_list, g_variant_get_handle(arg_stream), &err);
126132
if (err) {
127133
g_dbus_method_invocation_return_error(
@@ -131,24 +137,32 @@ dbus_chr_register(
131137
"Couldn't get peer FD: %s", err->message);
132138
return DBUS_METHOD_INVOCATION_HANDLED;
133139
}
140+
#endif
134141

135142
if (qemu_chr_add_client(CHARDEV(dc), fd) < 0) {
136143
g_dbus_method_invocation_return_error(invocation,
137144
DBUS_DISPLAY_ERROR,
138145
DBUS_DISPLAY_ERROR_FAILED,
139146
"Couldn't register FD!");
147+
#ifdef G_OS_WIN32
148+
closesocket(fd);
149+
#else
140150
close(fd);
151+
#endif
141152
return DBUS_METHOD_INVOCATION_HANDLED;
142153
}
143154

144155
g_object_set(dc->iface,
145156
"owner", g_dbus_method_invocation_get_sender(invocation),
146157
NULL);
147158

148-
qemu_dbus_display1_chardev_complete_register(object, invocation, NULL);
159+
qemu_dbus_display1_chardev_complete_register(object, invocation
160+
#ifndef G_OS_WIN32
161+
, NULL
162+
#endif
163+
);
149164
return DBUS_METHOD_INVOCATION_HANDLED;
150165
}
151-
#endif
152166

153167
static gboolean
154168
dbus_chr_send_break(
@@ -179,10 +193,8 @@ dbus_chr_open(Chardev *chr, ChardevBackend *backend,
179193
dc->iface = qemu_dbus_display1_chardev_skeleton_new();
180194
g_object_set(dc->iface, "name", backend->u.dbus.data->name, NULL);
181195
g_object_connect(dc->iface,
182-
#ifdef G_OS_UNIX
183196
"swapped-signal::handle-register",
184197
dbus_chr_register, dc,
185-
#endif
186198
"swapped-signal::handle-send-break",
187199
dbus_chr_send_break, dc,
188200
NULL);

ui/dbus-console.c

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,6 @@ dbus_display_console_class_init(DBusDisplayConsoleClass *klass)
165165
gobject_class->dispose = dbus_display_console_dispose;
166166
}
167167

168-
#ifdef G_OS_UNIX
169168
static void
170169
listener_vanished_cb(DBusDisplayListener *listener)
171170
{
@@ -177,7 +176,6 @@ listener_vanished_cb(DBusDisplayListener *listener)
177176
g_hash_table_remove(ddc->listeners, name);
178177
qkbd_state_lift_all_keys(ddc->kbd);
179178
}
180-
#endif
181179

182180
static gboolean
183181
dbus_console_set_ui_info(DBusDisplayConsole *ddc,
@@ -211,11 +209,47 @@ dbus_console_set_ui_info(DBusDisplayConsole *ddc,
211209
return DBUS_METHOD_INVOCATION_HANDLED;
212210
}
213211

214-
#ifdef G_OS_UNIX
212+
#ifdef G_OS_WIN32
213+
bool
214+
dbus_win32_import_socket(GDBusMethodInvocation *invocation,
215+
GVariant *arg_listener, int *socket)
216+
{
217+
gsize n;
218+
WSAPROTOCOL_INFOW *info = (void *)g_variant_get_fixed_array(arg_listener, &n, 1);
219+
220+
if (!info || n != sizeof(*info)) {
221+
g_dbus_method_invocation_return_error(
222+
invocation,
223+
DBUS_DISPLAY_ERROR,
224+
DBUS_DISPLAY_ERROR_FAILED,
225+
"Failed to get socket infos");
226+
return false;
227+
}
228+
229+
*socket = WSASocketW(FROM_PROTOCOL_INFO,
230+
FROM_PROTOCOL_INFO,
231+
FROM_PROTOCOL_INFO,
232+
info, 0, 0);
233+
if (*socket == INVALID_SOCKET) {
234+
g_autofree gchar *emsg = g_win32_error_message(WSAGetLastError());
235+
g_dbus_method_invocation_return_error(
236+
invocation,
237+
DBUS_DISPLAY_ERROR,
238+
DBUS_DISPLAY_ERROR_FAILED,
239+
"Couldn't create socket: %s", emsg);
240+
return false;
241+
}
242+
243+
return true;
244+
}
245+
#endif
246+
215247
static gboolean
216248
dbus_console_register_listener(DBusDisplayConsole *ddc,
217249
GDBusMethodInvocation *invocation,
250+
#ifdef G_OS_UNIX
218251
GUnixFDList *fd_list,
252+
#endif
219253
GVariant *arg_listener)
220254
{
221255
const char *sender = g_dbus_method_invocation_get_sender(invocation);
@@ -237,6 +271,11 @@ dbus_console_register_listener(DBusDisplayConsole *ddc,
237271
return DBUS_METHOD_INVOCATION_HANDLED;
238272
}
239273

274+
#ifdef G_OS_WIN32
275+
if (!dbus_win32_import_socket(invocation, arg_listener, &fd)) {
276+
return DBUS_METHOD_INVOCATION_HANDLED;
277+
}
278+
#else
240279
fd = g_unix_fd_list_get(fd_list, g_variant_get_handle(arg_listener), &err);
241280
if (err) {
242281
g_dbus_method_invocation_return_error(
@@ -246,6 +285,7 @@ dbus_console_register_listener(DBusDisplayConsole *ddc,
246285
"Couldn't get peer fd: %s", err->message);
247286
return DBUS_METHOD_INVOCATION_HANDLED;
248287
}
288+
#endif
249289

250290
socket = g_socket_new_from_fd(fd, &err);
251291
if (err) {
@@ -254,13 +294,21 @@ dbus_console_register_listener(DBusDisplayConsole *ddc,
254294
DBUS_DISPLAY_ERROR,
255295
DBUS_DISPLAY_ERROR_FAILED,
256296
"Couldn't make a socket: %s", err->message);
297+
#ifdef G_OS_WIN32
298+
closesocket(fd);
299+
#else
257300
close(fd);
301+
#endif
258302
return DBUS_METHOD_INVOCATION_HANDLED;
259303
}
260304
socket_conn = g_socket_connection_factory_create_connection(socket);
261305

262306
qemu_dbus_display1_console_complete_register_listener(
263-
ddc->iface, invocation, NULL);
307+
ddc->iface, invocation
308+
#ifdef G_OS_UNIX
309+
, NULL
310+
#endif
311+
);
264312

265313
listener_conn = g_dbus_connection_new_sync(
266314
G_IO_STREAM(socket_conn),
@@ -287,7 +335,6 @@ dbus_console_register_listener(DBusDisplayConsole *ddc,
287335
trace_dbus_registered_listener(sender);
288336
return DBUS_METHOD_INVOCATION_HANDLED;
289337
}
290-
#endif
291338

292339
static gboolean
293340
dbus_kbd_press(DBusDisplayConsole *ddc,
@@ -516,10 +563,8 @@ dbus_display_console_new(DBusDisplay *display, QemuConsole *con)
516563
"device-address", device_addr,
517564
NULL);
518565
g_object_connect(ddc->iface,
519-
#ifdef G_OS_UNIX
520566
"swapped-signal::handle-register-listener",
521567
dbus_console_register_listener, ddc,
522-
#endif
523568
"swapped-signal::handle-set-uiinfo",
524569
dbus_console_set_ui_info, ddc,
525570
NULL);

0 commit comments

Comments
 (0)