From d409373b9d0482bbce312539d02a648cbb1c790a Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 2 Aug 2022 15:51:58 +0800 Subject: util/qemu-sockets: Enable unix socket support on Windows Support for the unix socket has existed both in BSD and Linux for the longest time, but not on Windows. Since Windows 10 build 17063 [1], the native support for the unix socket has come to Windows. Starting this build, two Win32 processes can use the AF_UNIX address family over Winsock API to communicate with each other. [1] https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/ Signed-off-by: Xuzhou Cheng Signed-off-by: Bin Meng Reviewed-by: Marc-André Lureau Message-Id: <20220802075200.907360-3-bmeng.cn@gmail.com> --- include/sysemu/os-win32.h | 17 +++++++++++++++++ meson.build | 3 +++ util/qemu-sockets.c | 25 ------------------------- 3 files changed, 20 insertions(+), 25 deletions(-) diff --git a/include/sysemu/os-win32.h b/include/sysemu/os-win32.h index edc3b38a57..5b38c7bd04 100644 --- a/include/sysemu/os-win32.h +++ b/include/sysemu/os-win32.h @@ -30,6 +30,23 @@ #include #include +#ifdef HAVE_AFUNIX_H +#include +#else +/* + * Fallback definitions of things we need in afunix.h, if not available from + * the used Windows SDK or MinGW headers. + */ +#define UNIX_PATH_MAX 108 + +typedef struct sockaddr_un { + ADDRESS_FAMILY sun_family; + char sun_path[UNIX_PATH_MAX]; +} SOCKADDR_UN, *PSOCKADDR_UN; + +#define SIO_AF_UNIX_GETPEERPID _WSAIOR(IOC_VENDOR, 256) +#endif + #ifdef __cplusplus extern "C" { #endif diff --git a/meson.build b/meson.build index 20fddbd707..169b18a279 100644 --- a/meson.build +++ b/meson.build @@ -1890,6 +1890,9 @@ config_host_data.set('HAVE_PTY_H', cc.has_header('pty.h')) config_host_data.set('HAVE_SYS_DISK_H', cc.has_header('sys/disk.h')) config_host_data.set('HAVE_SYS_IOCCOM_H', cc.has_header('sys/ioccom.h')) config_host_data.set('HAVE_SYS_KCOV_H', cc.has_header('sys/kcov.h')) +if targetos == 'windows' + config_host_data.set('HAVE_AFUNIX_H', cc.has_header('afunix.h')) +endif # has_function config_host_data.set('CONFIG_ACCEPT4', cc.has_function('accept4')) diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index 0e2298278f..83f4bd6fd2 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -880,8 +880,6 @@ static int vsock_parse(VsockSocketAddress *addr, const char *str, } #endif /* CONFIG_AF_VSOCK */ -#ifndef _WIN32 - static bool saddr_is_abstract(UnixSocketAddress *saddr) { #ifdef CONFIG_LINUX @@ -1054,25 +1052,6 @@ static int unix_connect_saddr(UnixSocketAddress *saddr, Error **errp) return -1; } -#else - -static int unix_listen_saddr(UnixSocketAddress *saddr, - int num, - Error **errp) -{ - error_setg(errp, "unix sockets are not available on windows"); - errno = ENOTSUP; - return -1; -} - -static int unix_connect_saddr(UnixSocketAddress *saddr, Error **errp) -{ - error_setg(errp, "unix sockets are not available on windows"); - errno = ENOTSUP; - return -1; -} -#endif - /* compatibility wrapper */ int unix_listen(const char *str, Error **errp) { @@ -1335,7 +1314,6 @@ socket_sockaddr_to_address_inet(struct sockaddr_storage *sa, } -#ifndef WIN32 static SocketAddress * socket_sockaddr_to_address_unix(struct sockaddr_storage *sa, socklen_t salen, @@ -1362,7 +1340,6 @@ socket_sockaddr_to_address_unix(struct sockaddr_storage *sa, addr->u.q_unix.path = g_strndup(su->sun_path, salen); return addr; } -#endif /* WIN32 */ #ifdef CONFIG_AF_VSOCK static SocketAddress * @@ -1394,10 +1371,8 @@ socket_sockaddr_to_address(struct sockaddr_storage *sa, case AF_INET6: return socket_sockaddr_to_address_inet(sa, salen, errp); -#ifndef WIN32 case AF_UNIX: return socket_sockaddr_to_address_unix(sa, salen, errp); -#endif /* WIN32 */ #ifdef CONFIG_AF_VSOCK case AF_VSOCK: -- cgit v1.2.3-55-g7522 From 120fa5e0e6ebacd811e4d830cff8a405806d305c Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 2 Aug 2022 15:51:59 +0800 Subject: chardev/char-socket: Update AF_UNIX for Windows Now that AF_UNIX has come to Windows, update the existing logic in qemu_chr_compute_filename() and qmp_chardev_open_socket() for Windows. Signed-off-by: Bin Meng Reviewed-by: Marc-André Lureau Message-Id: <20220802075200.907360-4-bmeng.cn@gmail.com> --- chardev/char-socket.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chardev/char-socket.c b/chardev/char-socket.c index dc4e218eeb..879564aa8a 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -557,12 +557,10 @@ static char *qemu_chr_compute_filename(SocketChardev *s) const char *left = "", *right = ""; switch (ss->ss_family) { -#ifndef _WIN32 case AF_UNIX: return g_strdup_printf("unix:%s%s", ((struct sockaddr_un *)(ss))->sun_path, s->is_listen ? ",server=on" : ""); -#endif case AF_INET6: left = "["; right = "]"; @@ -1372,10 +1370,12 @@ static void qmp_chardev_open_socket(Chardev *chr, } qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_RECONNECTABLE); +#ifndef _WIN32 /* TODO SOCKET_ADDRESS_FD where fd has AF_UNIX */ if (addr->type == SOCKET_ADDRESS_TYPE_UNIX) { qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_FD_PASS); } +#endif /* * In the chardev-change special-case, we shouldn't register a new yank -- cgit v1.2.3-55-g7522 From 0370f239ad14aeacc496775e241b9ef041df4374 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 2 Aug 2022 15:52:00 +0800 Subject: tests/unit: Update test-io-channel-socket.c for Windows Change to dynamically include the test cases by checking AF_UNIX availability using a new helper socket_check_afunix_support(). With such changes testing on a Windows host can be covered as well. Signed-off-by: Bin Meng Reviewed-by: Marc-André Lureau Message-Id: <20220802075200.907360-5-bmeng.cn@gmail.com> --- tests/unit/socket-helpers.c | 16 ++++++++++++++++ tests/unit/socket-helpers.h | 9 +++++++++ tests/unit/test-io-channel-socket.c | 37 +++++++++++++++++++++++-------------- 3 files changed, 48 insertions(+), 14 deletions(-) diff --git a/tests/unit/socket-helpers.c b/tests/unit/socket-helpers.c index 5af4de513b..eecadf3a3c 100644 --- a/tests/unit/socket-helpers.c +++ b/tests/unit/socket-helpers.c @@ -154,3 +154,19 @@ int socket_check_protocol_support(bool *has_ipv4, bool *has_ipv6) return 0; } + +void socket_check_afunix_support(bool *has_afunix) +{ + int fd; + + fd = socket(PF_UNIX, SOCK_STREAM, 0); + closesocket(fd); + +#ifdef _WIN32 + *has_afunix = (fd != (int)INVALID_SOCKET); +#else + *has_afunix = (fd >= 0); +#endif + + return; +} diff --git a/tests/unit/socket-helpers.h b/tests/unit/socket-helpers.h index 512a004811..ed8477ceb3 100644 --- a/tests/unit/socket-helpers.h +++ b/tests/unit/socket-helpers.h @@ -32,4 +32,13 @@ */ int socket_check_protocol_support(bool *has_ipv4, bool *has_ipv6); +/* + * @has_afunix: set to true on return if unix socket support is available + * + * Check whether unix domain socket support is available for use. + * On success, @has_afunix will be set to indicate whether AF_UNIX protocol + * is available. + */ +void socket_check_afunix_support(bool *has_afunix); + #endif diff --git a/tests/unit/test-io-channel-socket.c b/tests/unit/test-io-channel-socket.c index 6713886d02..b36a5d972a 100644 --- a/tests/unit/test-io-channel-socket.c +++ b/tests/unit/test-io-channel-socket.c @@ -179,10 +179,12 @@ static void test_io_channel(bool async, test_io_channel_setup_async(listen_addr, connect_addr, &srv, &src, &dst); +#ifndef _WIN32 g_assert(!passFD || qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS)); g_assert(!passFD || qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS)); +#endif g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN)); g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN)); @@ -206,10 +208,12 @@ static void test_io_channel(bool async, test_io_channel_setup_async(listen_addr, connect_addr, &srv, &src, &dst); +#ifndef _WIN32 g_assert(!passFD || qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS)); g_assert(!passFD || qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS)); +#endif g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN)); g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN)); @@ -236,10 +240,12 @@ static void test_io_channel(bool async, test_io_channel_setup_sync(listen_addr, connect_addr, &srv, &src, &dst); +#ifndef _WIN32 g_assert(!passFD || qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS)); g_assert(!passFD || qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS)); +#endif g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN)); g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN)); @@ -263,10 +269,12 @@ static void test_io_channel(bool async, test_io_channel_setup_sync(listen_addr, connect_addr, &srv, &src, &dst); +#ifndef _WIN32 g_assert(!passFD || qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS)); g_assert(!passFD || qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS)); +#endif g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN)); g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN)); @@ -367,7 +375,6 @@ static void test_io_channel_ipv6_async(void) } -#ifndef _WIN32 static void test_io_channel_unix(bool async) { SocketAddress *listen_addr = g_new0(SocketAddress, 1); @@ -398,6 +405,7 @@ static void test_io_channel_unix_async(void) return test_io_channel_unix(true); } +#ifndef _WIN32 static void test_io_channel_unix_fd_pass(void) { SocketAddress *listen_addr = g_new0(SocketAddress, 1); @@ -491,6 +499,7 @@ static void test_io_channel_unix_fd_pass(void) } g_free(fdrecv); } +#endif /* _WIN32 */ static void test_io_channel_unix_listen_cleanup(void) { @@ -522,9 +531,6 @@ static void test_io_channel_unix_listen_cleanup(void) unlink(TEST_SOCKET); } -#endif /* _WIN32 */ - - static void test_io_channel_ipv4_fd(void) { QIOChannel *ioc; @@ -555,7 +561,7 @@ static void test_io_channel_ipv4_fd(void) int main(int argc, char **argv) { - bool has_ipv4, has_ipv6; + bool has_ipv4, has_ipv6, has_afunix; module_call_init(MODULE_INIT_QOM); qemu_init_main_loop(&error_abort); @@ -588,16 +594,19 @@ int main(int argc, char **argv) test_io_channel_ipv6_async); } + socket_check_afunix_support(&has_afunix); + if (has_afunix) { + g_test_add_func("/io/channel/socket/unix-sync", + test_io_channel_unix_sync); + g_test_add_func("/io/channel/socket/unix-async", + test_io_channel_unix_async); #ifndef _WIN32 - g_test_add_func("/io/channel/socket/unix-sync", - test_io_channel_unix_sync); - g_test_add_func("/io/channel/socket/unix-async", - test_io_channel_unix_async); - g_test_add_func("/io/channel/socket/unix-fd-pass", - test_io_channel_unix_fd_pass); - g_test_add_func("/io/channel/socket/unix-listen-cleanup", - test_io_channel_unix_listen_cleanup); -#endif /* _WIN32 */ + g_test_add_func("/io/channel/socket/unix-fd-pass", + test_io_channel_unix_fd_pass); +#endif + g_test_add_func("/io/channel/socket/unix-listen-cleanup", + test_io_channel_unix_listen_cleanup); + } end: return g_test_run(); -- cgit v1.2.3-55-g7522 From 0f957c53c84d655f2e99677d407cf2bbe1832de4 Mon Sep 17 00:00:00 2001 From: Marc-André Lureau Date: Mon, 22 Aug 2022 17:10:21 +0400 Subject: audio: exit(1) if audio backend failed to be found or initialized If you specify a known backend but it isn't compiled in, or failed to initialize, you get a simple warning and the "none" backend as a fallback, and QEMU runs happily: $ qemu-system-x86_64 -audiodev id=audio,driver=dsound audio: Unknown audio driver `dsound' audio: warning: Using timer based audio emulation ... Instead, QEMU should fail to start: $ qemu-system-x86_64 -audiodev id=audio,driver=dsound audio: Unknown audio driver `dsound' $ Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1983493 Signed-off-by: Marc-André Lureau Reviewed-by: Volker Rümelin Message-Id: <20220822131021.975656-1-marcandre.lureau@redhat.com> --- audio/audio.c | 14 +++++++++++--- audio/audio.h | 2 +- softmmu/vl.c | 4 +++- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index a02f3ce5c6..76b8735b44 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -1743,7 +1743,6 @@ static AudioState *audio_init(Audiodev *dev, const char *name) atexit(audio_cleanup); atexit_registered = true; } - QTAILQ_INSERT_TAIL(&audio_states, s, list); s->ts = timer_new_ns(QEMU_CLOCK_VIRTUAL, audio_timer, s); @@ -1769,6 +1768,10 @@ static AudioState *audio_init(Audiodev *dev, const char *name) } else { dolog ("Unknown audio driver `%s'\n", drvname); } + if (!done) { + free_audio_state(s); + return NULL; + } } else { for (i = 0; audio_prio_list[i]; i++) { AudiodevListEntry *e = audiodev_find(&head, audio_prio_list[i]); @@ -1806,6 +1809,7 @@ static AudioState *audio_init(Audiodev *dev, const char *name) "(Audio can continue looping even after stopping the VM)\n"); } + QTAILQ_INSERT_TAIL(&audio_states, s, list); QLIST_INIT (&s->card_head); vmstate_register (NULL, 0, &vmstate_audio, s); return s; @@ -2119,13 +2123,17 @@ void audio_define(Audiodev *dev) QSIMPLEQ_INSERT_TAIL(&audiodevs, e, next); } -void audio_init_audiodevs(void) +bool audio_init_audiodevs(void) { AudiodevListEntry *e; QSIMPLEQ_FOREACH(e, &audiodevs, next) { - audio_init(e->dev, NULL); + if (!audio_init(e->dev, NULL)) { + return false; + } } + + return true; } audsettings audiodev_to_audsettings(AudiodevPerDirectionOptions *pdo) diff --git a/audio/audio.h b/audio/audio.h index b5e17cd218..27e67079a0 100644 --- a/audio/audio.h +++ b/audio/audio.h @@ -170,7 +170,7 @@ void audio_sample_from_uint64(void *samples, int pos, void audio_define(Audiodev *audio); void audio_parse_option(const char *opt); -void audio_init_audiodevs(void); +bool audio_init_audiodevs(void); void audio_legacy_help(void); AudioState *audio_state_by_name(const char *name); diff --git a/softmmu/vl.c b/softmmu/vl.c index 706bd7cff7..dea4005e47 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -1885,7 +1885,9 @@ static void qemu_create_early_backends(void) * setting machine properties, so they can be referred to. */ configure_blockdev(&bdo_queue, machine_class, snapshot); - audio_init_audiodevs(); + if (!audio_init_audiodevs()) { + exit(1); + } } -- cgit v1.2.3-55-g7522