qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] net: fix multicast support with BSD (macOS) socket implementatio


From: Vitaly Cheptsov
Subject: [PATCH] net: fix multicast support with BSD (macOS) socket implementations
Date: Mon, 2 May 2022 03:38:30 +0300

This patch fixes socket communication with QEMU -> host on macOS,
which was originally impossible due to QEMU and host program
having to bind to the same ip/port in a way not supported by BSD
sockets. The change was tested on both Linux and macOS.

As per BSD manual pages SO_REUSEPORT allows completely duplicate
bindings by multiple processes, permitting multiple instances of
a program to each receive UDP/IP multicast datagrams destined
for the bound port. Without this option macOS, unlike Linux,
which (ab)uses SO_REUSEADDR for this purpose, will return
"Address already in use" on bind().

As per BSD manual pages binding to any address, even one not bound
to any available network interface in the system, should be
IP_BINDANY. Without binding to INADDR_ANY macOS will return
"Can't assign requested address" on send().

Cc: Jason Wang <jasowang@redhat.com>
Cc: Daniel P. Berrange <berrange@redhat.com>
Cc: Philippe Mathieu-Daudé <f4bug@amsat.org>
Signed-off-by: Vitaly Cheptsov <cheptsov@ispras.ru>
---
 net/socket.c | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/net/socket.c b/net/socket.c
index ea5220a2eb..8b2c6c4bb8 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -252,10 +252,24 @@ static int net_socket_mcast_create(struct sockaddr_in 
*mcastaddr,
         goto fail;
     }
 
-    ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr));
+    val = 1;
+    ret = qemu_setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val));
+    if (ret < 0) {
+        error_setg_errno(errp, errno,
+                         "can't set socket option SO_REUSEPORT");
+        goto fail;
+    }
+
+    struct sockaddr_in bindaddr;
+    memset(&bindaddr, 0, sizeof(bindaddr));
+    bindaddr.sin_family = AF_INET;
+    bindaddr.sin_addr.s_addr = htonl(INADDR_ANY);
+    bindaddr.sin_port = mcastaddr->sin_port;
+    ret = bind(fd, (struct sockaddr *)&bindaddr, sizeof(bindaddr));
+
     if (ret < 0) {
         error_setg_errno(errp, errno, "can't bind ip=%s to socket",
-                         inet_ntoa(mcastaddr->sin_addr));
+                         inet_ntoa(bindaddr.sin_addr));
         goto fail;
     }
 
-- 
2.32.0 (Apple Git-132)




reply via email to

[Prev in Thread] Current Thread [Next in Thread]