From 8d8d5491f9624d994ffa7a53d9aa2c93f6b41a07 Mon Sep 17 00:00:00 2001 From: Igor Katson Date: Sun, 15 Sep 2024 22:28:43 +0100 Subject: [PATCH] trying to fix windows multicast --- Cargo.lock | 1 + crates/upnp-serve/Cargo.toml | 3 +++ crates/upnp-serve/src/ssdp.rs | 50 ++++++++++++++++++++++++----------- 3 files changed, 38 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2e00a74..05b39cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2710,6 +2710,7 @@ dependencies = [ "tracing-subscriber", "url", "uuid", + "winapi", ] [[package]] diff --git a/crates/upnp-serve/Cargo.toml b/crates/upnp-serve/Cargo.toml index c2edf93..2ff0b22 100644 --- a/crates/upnp-serve/Cargo.toml +++ b/crates/upnp-serve/Cargo.toml @@ -41,6 +41,9 @@ network-interface = "2.0.0" futures = "0.3.30" libc = "0.2.158" +[target.'cfg(windows)'.dependencies] +winapi = { version = "0.3.9", features = ["winsock2"] } + [dev-dependencies] tracing-subscriber = "0.3.18" tower-http = { version = "0.5", features = ["trace"] } diff --git a/crates/upnp-serve/src/ssdp.rs b/crates/upnp-serve/src/ssdp.rs index 3ca75ff..37afb45 100644 --- a/crates/upnp-serve/src/ssdp.rs +++ b/crates/upnp-serve/src/ssdp.rs @@ -1,7 +1,6 @@ use std::{ collections::HashSet, net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}, - os::fd::{AsFd, AsRawFd}, time::Duration, }; @@ -217,24 +216,43 @@ struct MulticastOpts { addr: SocketAddr, } -fn set_mcast_if(sock: &UdpSocket, local_ip: Ipv4Addr) -> std::io::Result<()> { - let addr = libc::in_addr { - s_addr: u32::from_ne_bytes(local_ip.octets()), - }; - const SZ: usize = std::mem::size_of::(); +fn set_mcast_if(sock: &UdpSocket, local_ip: Ipv4Addr) -> anyhow::Result<()> { + // in_addr is the same on unix and windows and contains just the 4 bytes of IPv4 in network + // byte order. + let addr = u32::from_ne_bytes(local_ip.octets()); + let sz: usize = std::mem::size_of_val(&addr); trace!(addr = %local_ip, "setting IP_MULTICAST_IF"); - let ret = unsafe { - libc::setsockopt( - sock.as_fd().as_raw_fd(), - libc::IPPROTO_IP, - libc::IP_MULTICAST_IF, - &addr as *const _ as _, - SZ as u32, - ) - }; + + let ret: i32; + #[cfg(target_os = "windows")] + { + use std::os::windows::io::AsRawSocket; + ret = unsafe { + winapi::um::winsock2::setsockopt( + sock.as_raw_socket().try_into()?, + winapi::shared::ws2def::IPPROTO_IP, + winapi::shared::ws2ipdef::IP_MULTICAST_IF, + &addr as *const _ as _, + sz.try_into()?, + ) + }; + } + #[cfg(not(target_os = "windows"))] + { + use std::os::fd::{AsFd, AsRawFd}; + ret = unsafe { + libc::setsockopt( + sock.as_fd().as_raw_fd(), + libc::IPPROTO_IP, + libc::IP_MULTICAST_IF, + &addr as *const _ as _, + sz.try_into()?, + ) + }; + } if ret < 0 { - return Err(std::io::Error::last_os_error()); + return Err(std::io::Error::last_os_error().into()); } Ok(()) }