From 36d8243397f99229d3d33e6ab71c2756bcd643a5 Mon Sep 17 00:00:00 2001 From: Taruntej Kanakamalla Date: Thu, 7 Nov 2024 15:44:25 +0530 Subject: [PATCH] ptp: use ip_mreq instead of ip_mreqn for macOS To join a multicast the macOS still uses the interface address from the ip_mreq instead of the ip_mreqn unlike other Linux systems. So add a new conditional block for macOS to use ip_mreq for IP_ADD_MEMBERSHIP and ip_mreqn for IP_MULTICAST_IF This is similar to the fix in the glib for multicast join/leave operation on macOS https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4333 Part-of: --- .../gstreamer/libs/gst/helpers/ptp/ffi.rs | 9 +++ .../gstreamer/libs/gst/helpers/ptp/net.rs | 74 +++++++++++++++++-- 2 files changed, 75 insertions(+), 8 deletions(-) diff --git a/subprojects/gstreamer/libs/gst/helpers/ptp/ffi.rs b/subprojects/gstreamer/libs/gst/helpers/ptp/ffi.rs index 41f1c61f6d..be527beb1c 100644 --- a/subprojects/gstreamer/libs/gst/helpers/ptp/ffi.rs +++ b/subprojects/gstreamer/libs/gst/helpers/ptp/ffi.rs @@ -376,6 +376,15 @@ pub mod unix { pub imr_ifindex: c_int, } + // macOS uses ip_mreq instead of ip_mreqn in its latest version of the MAC Kernel for IP_ADD_MEMBERSHIP + #[cfg(target_os = "macos")] + #[repr(C)] + #[derive(Copy, Clone)] + pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_address: in_addr, + } + #[cfg(any(target_os = "solaris", target_os = "illumos"))] #[repr(C)] pub struct ifaddrs { diff --git a/subprojects/gstreamer/libs/gst/helpers/ptp/net.rs b/subprojects/gstreamer/libs/gst/helpers/ptp/net.rs index a9fade79f8..258abceb00 100644 --- a/subprojects/gstreamer/libs/gst/helpers/ptp/net.rs +++ b/subprojects/gstreamer/libs/gst/helpers/ptp/net.rs @@ -376,7 +376,7 @@ mod imp { addr: &Ipv4Addr, iface: &InterfaceInfo, ) -> Result<(), Error> { - #[cfg(not(any(target_os = "solaris", target_os = "illumos")))] + #[cfg(not(any(target_os = "solaris", target_os = "illumos", target_os = "macos")))] { let mreqn = ip_mreqn { imr_multiaddr: in_addr { @@ -408,12 +408,7 @@ mod imp { } } - #[cfg(not(any( - target_os = "openbsd", - target_os = "dragonfly", - target_os = "netbsd", - target_os = "macos" - )))] + #[cfg(not(any(target_os = "openbsd", target_os = "dragonfly", target_os = "netbsd")))] { let mreqn = ip_mreqn { imr_multiaddr: in_addr { @@ -445,7 +440,7 @@ mod imp { } } } - #[cfg(any(target_os = "openbsd", target_os = "dragonfly", target_os = "macos"))] + #[cfg(any(target_os = "openbsd", target_os = "dragonfly"))] { let addr = in_addr { s_addr: u32::from_ne_bytes(iface.ip_addr.octets()), @@ -534,6 +529,69 @@ mod imp { Ok(()) } + + #[cfg(target_os = "macos")] + { + let mreq = ip_mreq { + imr_multiaddr: in_addr { + s_addr: u32::from_ne_bytes(addr.octets()), + }, + imr_address: in_addr { + s_addr: u32::from_ne_bytes(iface.ip_addr.octets()), + }, + }; + + let mreqn = ip_mreqn { + imr_multiaddr: in_addr { + s_addr: u32::from_ne_bytes(Ipv4Addr::UNSPECIFIED.octets()), + }, + imr_address: in_addr { + s_addr: u32::from_ne_bytes(Ipv4Addr::UNSPECIFIED.octets()), + }, + imr_ifindex: iface.index as _, + }; + + // SAFETY: Requires a valid ip_mreq struct to be passed together with its size for checking + // validity. On errors a negative integer is returned. + unsafe { + if setsockopt( + socket.as_raw_fd(), + IPPROTO_IP, + IP_ADD_MEMBERSHIP, + &mreq as *const _ as *const _, + mem::size_of_val(&mreq) as _, + ) < 0 + { + bail!( + source: io::Error::last_os_error(), + "Failed joining multicast group for interface {}", + iface.name, + ); + } + } + + // SAFETY: Requires a valid ip_mreqn struct to be passed together + // with its size for checking which of the two it is. On errors a negative + // integer is returned. + unsafe { + if setsockopt( + socket.as_raw_fd(), + IPPROTO_IP, + IP_MULTICAST_IF, + &mreqn as *const _ as *const _, + mem::size_of_val(&mreqn) as _, + ) < 0 + { + bail!( + source: io::Error::last_os_error(), + "Failed joining multicast group for interface {}", + iface.name, + ); + } + } + + Ok(()) + } } /// Allow multiple sockets to bind to the same address / port.