aboutsummaryrefslogtreecommitdiff
path: root/util
diff options
context:
space:
mode:
Diffstat (limited to 'util')
-rw-r--r--util/qemu-sockets.c31
1 files changed, 23 insertions, 8 deletions
diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
index 55b6c17..3d2e511 100644
--- a/util/qemu-sockets.c
+++ b/util/qemu-sockets.c
@@ -208,22 +208,37 @@ static int inet_listen_saddr(InetSocketAddress *saddr,
}
socket_set_fast_reuse(slisten);
-#ifdef IPV6_V6ONLY
- if (e->ai_family == PF_INET6) {
- /* listen on both ipv4 and ipv6 */
- const int off = 0;
- qemu_setsockopt(slisten, IPPROTO_IPV6, IPV6_V6ONLY, &off,
- sizeof(off));
- }
-#endif
port_min = inet_getport(e);
port_max = saddr->has_to ? saddr->to + port_offset : port_min;
for (p = port_min; p <= port_max; p++) {
+#ifdef IPV6_V6ONLY
+ /* listen on both ipv4 and ipv6 */
+ int v6only = 0;
+#endif
inet_setport(e, p);
+#ifdef IPV6_V6ONLY
+ rebind:
+ if (e->ai_family == PF_INET6) {
+ qemu_setsockopt(slisten, IPPROTO_IPV6, IPV6_V6ONLY, &v6only,
+ sizeof(v6only));
+ }
+#endif
if (bind(slisten, e->ai_addr, e->ai_addrlen) == 0) {
goto listen;
}
+
+#ifdef IPV6_V6ONLY
+ /* If we got EADDRINUSE from an IPv6 bind & V6ONLY is unset,
+ * it could be that the IPv4 port is already claimed, so retry
+ * with V6ONLY set
+ */
+ if (e->ai_family == PF_INET6 && errno == EADDRINUSE && !v6only) {
+ v6only = 1;
+ goto rebind;
+ }
+#endif
+
if (p == port_max) {
if (!e->ai_next) {
error_setg_errno(errp, errno, "Failed to bind socket");