From 85b923a8431c417512bad899e3acff997bc32266 Mon Sep 17 00:00:00 2001 From: Han Xu Date: Mon, 14 Dec 2020 22:50:24 -0800 Subject: [PATCH 1/7] add IP_MULTICAST_IF for sockopt --- src/sys/socket/mod.rs | 18 ++++++++++++++++++ src/sys/socket/sockopt.rs | 1 + 2 files changed, 19 insertions(+) diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index a4f599c130..2afec3295a 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -375,6 +375,24 @@ impl Ipv6MembershipRequest { } } +/// Request for multicast socket's outgoing interface +/// +/// Normally the value is an `in_addr` structure, but +/// Linux also supports an ip_mreqn or (since Linux 3.5) ip_mreq +/// structure, hence define an enum to support future expansions. +#[repr(transparent)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum IpMulticastIfRequest { + IN_ADDR(libc::in_addr), +} + +impl IpMulticastIfRequest { + /// Instantiate a new `IpMulticastIfRequest::IN_ADDR` + pub fn new_in_addr(interface: Ipv4Addr) -> Self { + IpMulticastIfRequest::IN_ADDR(interface.0) + } +} + /// Create a buffer large enough for storing some control messages as returned /// by [`recvmsg`](fn.recvmsg.html). /// diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index 5b7b4feafb..d686900049 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -233,6 +233,7 @@ cfg_if! { sockopt_impl!(SetOnly, Ipv6DropMembership, libc::IPPROTO_IPV6, libc::IPV6_LEAVE_GROUP, super::Ipv6MembershipRequest); } } +sockopt_impl!(Both, IpMulticastIf, libc::IPPROTO_IP, libc::IP_MULTICAST_IF, super::IpMulticastIfRequest); sockopt_impl!(Both, IpMulticastTtl, libc::IPPROTO_IP, libc::IP_MULTICAST_TTL, u8); sockopt_impl!(Both, IpMulticastLoop, libc::IPPROTO_IP, libc::IP_MULTICAST_LOOP, bool); sockopt_impl!(Both, ReceiveTimeout, libc::SOL_SOCKET, libc::SO_RCVTIMEO, TimeVal); From 6d64e8a28ec5f536075a5353b758af372d087138 Mon Sep 17 00:00:00 2001 From: Han Xu Date: Mon, 14 Dec 2020 23:16:38 -0800 Subject: [PATCH 2/7] remove repr(transparent) as it is unstable for Enum --- src/sys/socket/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 2afec3295a..9763afdfaf 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -380,7 +380,6 @@ impl Ipv6MembershipRequest { /// Normally the value is an `in_addr` structure, but /// Linux also supports an ip_mreqn or (since Linux 3.5) ip_mreq /// structure, hence define an enum to support future expansions. -#[repr(transparent)] #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum IpMulticastIfRequest { IN_ADDR(libc::in_addr), From 9a5dfad4e8f7b5665c9813d07efef0f590ce5fbe Mon Sep 17 00:00:00 2001 From: Han Xu Date: Wed, 23 Dec 2020 08:00:17 -0800 Subject: [PATCH 3/7] add test case --- test/sys/test_sockopt.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/test/sys/test_sockopt.rs b/test/sys/test_sockopt.rs index 5606593132..b837574499 100644 --- a/test/sys/test_sockopt.rs +++ b/test/sys/test_sockopt.rs @@ -1,5 +1,6 @@ use rand::{thread_rng, Rng}; -use nix::sys::socket::{socket, sockopt, getsockopt, setsockopt, AddressFamily, SockType, SockFlag, SockProtocol}; +use nix::ifaddrs::getifaddrs; +use nix::sys::socket::{AddressFamily, IpAddr, IpMulticastIfRequest, SockAddr, SockFlag, SockProtocol, SockType, getsockopt, setsockopt, socket, sockopt}; #[cfg(any(target_os = "android", target_os = "linux"))] use crate::*; @@ -94,3 +95,19 @@ fn test_so_tcp_keepalive() { assert_eq!(getsockopt(fd, sockopt::TcpKeepInterval).unwrap(), x + 1); } } + +#[test] +fn test_so_multicast_if() { + let fd = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), None).unwrap(); + let addrs = getifaddrs().unwrap(); + + for if_addr in addrs { + if let Some(SockAddr::Inet(inet_addr)) = if_addr.address { + if let IpAddr::V4(ipv4_addr) = inet_addr.ip() { + let request = IpMulticastIfRequest::new_in_addr(ipv4_addr); + setsockopt(fd, sockopt::IpMulticastIf, &request).unwrap(); + assert_eq!(getsockopt(fd, sockopt::IpMulticastIf).unwrap(), request); + } + } + } +} From 5303e36ad5d9b0d8cc62cd240ff6944bc5cf120e Mon Sep 17 00:00:00 2001 From: Han Xu Date: Wed, 23 Dec 2020 21:46:01 -0800 Subject: [PATCH 4/7] simplify the value type and hope fix the testing --- src/sys/socket/mod.rs | 18 ++++++++---------- src/sys/socket/sockopt.rs | 2 +- test/sys/test_sockopt.rs | 4 ++-- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 9763afdfaf..cef7e08155 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -377,18 +377,16 @@ impl Ipv6MembershipRequest { /// Request for multicast socket's outgoing interface /// -/// Normally the value is an `in_addr` structure, but -/// Linux also supports an ip_mreqn or (since Linux 3.5) ip_mreq -/// structure, hence define an enum to support future expansions. +/// The value must be a `libc::in_addr` structure, which is the most common. +/// `ip_mreqn` or `ip_mreq` structure are not supported. One reason is that +/// `#[repr(transparent)]` does not support enum. +#[repr(transparent)] #[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum IpMulticastIfRequest { - IN_ADDR(libc::in_addr), -} +pub struct IpMulticastIfInAddr(libc::in_addr); -impl IpMulticastIfRequest { - /// Instantiate a new `IpMulticastIfRequest::IN_ADDR` - pub fn new_in_addr(interface: Ipv4Addr) -> Self { - IpMulticastIfRequest::IN_ADDR(interface.0) +impl IpMulticastIfInAddr { + pub fn new(interface: Ipv4Addr) -> Self { + IpMulticastIfInAddr(interface.0) } } diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index d686900049..be3cd8f186 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -233,7 +233,7 @@ cfg_if! { sockopt_impl!(SetOnly, Ipv6DropMembership, libc::IPPROTO_IPV6, libc::IPV6_LEAVE_GROUP, super::Ipv6MembershipRequest); } } -sockopt_impl!(Both, IpMulticastIf, libc::IPPROTO_IP, libc::IP_MULTICAST_IF, super::IpMulticastIfRequest); +sockopt_impl!(Both, IpMulticastIf, libc::IPPROTO_IP, libc::IP_MULTICAST_IF, super::IpMulticastIfInAddr); sockopt_impl!(Both, IpMulticastTtl, libc::IPPROTO_IP, libc::IP_MULTICAST_TTL, u8); sockopt_impl!(Both, IpMulticastLoop, libc::IPPROTO_IP, libc::IP_MULTICAST_LOOP, bool); sockopt_impl!(Both, ReceiveTimeout, libc::SOL_SOCKET, libc::SO_RCVTIMEO, TimeVal); diff --git a/test/sys/test_sockopt.rs b/test/sys/test_sockopt.rs index b837574499..836416a04c 100644 --- a/test/sys/test_sockopt.rs +++ b/test/sys/test_sockopt.rs @@ -1,6 +1,6 @@ use rand::{thread_rng, Rng}; use nix::ifaddrs::getifaddrs; -use nix::sys::socket::{AddressFamily, IpAddr, IpMulticastIfRequest, SockAddr, SockFlag, SockProtocol, SockType, getsockopt, setsockopt, socket, sockopt}; +use nix::sys::socket::{AddressFamily, IpAddr, IpMulticastIfInAddr, SockAddr, SockFlag, SockProtocol, SockType, getsockopt, setsockopt, socket, sockopt}; #[cfg(any(target_os = "android", target_os = "linux"))] use crate::*; @@ -104,7 +104,7 @@ fn test_so_multicast_if() { for if_addr in addrs { if let Some(SockAddr::Inet(inet_addr)) = if_addr.address { if let IpAddr::V4(ipv4_addr) = inet_addr.ip() { - let request = IpMulticastIfRequest::new_in_addr(ipv4_addr); + let request = IpMulticastIfInAddr::new(ipv4_addr); setsockopt(fd, sockopt::IpMulticastIf, &request).unwrap(); assert_eq!(getsockopt(fd, sockopt::IpMulticastIf).unwrap(), request); } From 073e6f56ddd2feda8fea51c370d6824da0c5db35 Mon Sep 17 00:00:00 2001 From: Han Xu Date: Wed, 23 Dec 2020 22:25:40 -0800 Subject: [PATCH 5/7] try to fix testing --- src/sys/socket/mod.rs | 32 +++++++++++++++++++++----------- src/sys/socket/sockopt.rs | 12 +++++++++++- test/sys/test_sockopt.rs | 7 +++++++ 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index cef7e08155..7d0d808715 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -375,18 +375,28 @@ impl Ipv6MembershipRequest { } } -/// Request for multicast socket's outgoing interface -/// -/// The value must be a `libc::in_addr` structure, which is the most common. -/// `ip_mreqn` or `ip_mreq` structure are not supported. One reason is that -/// `#[repr(transparent)]` does not support enum. -#[repr(transparent)] -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct IpMulticastIfInAddr(libc::in_addr); +cfg_if! { + if #[cfg(not(all(target_os = "linux", + target_env = "gnu", + any(target_arch = "mips", + target_arch = "mips64", + target_arch = "aarch64", + target_arch = "arm", + target_arch = "powerpc64"))))] { + /// Request for multicast socket's outgoing interface + /// + /// The value must be a `libc::in_addr` structure, which is the most common. + /// `ip_mreqn` or `ip_mreq` structure are not supported. One reason is that + /// `#[repr(transparent)]` does not support enum. + #[repr(transparent)] + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct IpMulticastIfInAddr(libc::in_addr); -impl IpMulticastIfInAddr { - pub fn new(interface: Ipv4Addr) -> Self { - IpMulticastIfInAddr(interface.0) + impl IpMulticastIfInAddr { + pub fn new(interface: Ipv4Addr) -> Self { + IpMulticastIfInAddr(interface.0) + } + } } } diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index be3cd8f186..e95cee888e 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -233,7 +233,17 @@ cfg_if! { sockopt_impl!(SetOnly, Ipv6DropMembership, libc::IPPROTO_IPV6, libc::IPV6_LEAVE_GROUP, super::Ipv6MembershipRequest); } } -sockopt_impl!(Both, IpMulticastIf, libc::IPPROTO_IP, libc::IP_MULTICAST_IF, super::IpMulticastIfInAddr); +cfg_if! { + if #[cfg(not(all(target_os = "linux", + target_env = "gnu", + any(target_arch = "mips", + target_arch = "mips64", + target_arch = "aarch64", + target_arch = "arm", + target_arch = "powerpc64"))))] { + sockopt_impl!(Both, IpMulticastIf, libc::IPPROTO_IP, libc::IP_MULTICAST_IF, super::IpMulticastIfInAddr); + } +} sockopt_impl!(Both, IpMulticastTtl, libc::IPPROTO_IP, libc::IP_MULTICAST_TTL, u8); sockopt_impl!(Both, IpMulticastLoop, libc::IPPROTO_IP, libc::IP_MULTICAST_LOOP, bool); sockopt_impl!(Both, ReceiveTimeout, libc::SOL_SOCKET, libc::SO_RCVTIMEO, TimeVal); diff --git a/test/sys/test_sockopt.rs b/test/sys/test_sockopt.rs index 836416a04c..1673089696 100644 --- a/test/sys/test_sockopt.rs +++ b/test/sys/test_sockopt.rs @@ -97,6 +97,13 @@ fn test_so_tcp_keepalive() { } #[test] +#[cfg(not(all(target_os = "linux", + target_env = "gnu", + any(target_arch = "mips", + target_arch = "mips64", + target_arch = "aarch64", + target_arch = "arm", + target_arch = "powerpc64"))))] fn test_so_multicast_if() { let fd = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), None).unwrap(); let addrs = getifaddrs().unwrap(); From 28fe25224ac95328ba7e1521550995d3d0f002e6 Mon Sep 17 00:00:00 2001 From: Han Xu Date: Thu, 24 Dec 2020 07:52:14 -0800 Subject: [PATCH 6/7] fix conditional imports in test --- test/sys/test_sockopt.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/test/sys/test_sockopt.rs b/test/sys/test_sockopt.rs index 1673089696..9f2e1f9de7 100644 --- a/test/sys/test_sockopt.rs +++ b/test/sys/test_sockopt.rs @@ -1,6 +1,14 @@ use rand::{thread_rng, Rng}; -use nix::ifaddrs::getifaddrs; -use nix::sys::socket::{AddressFamily, IpAddr, IpMulticastIfInAddr, SockAddr, SockFlag, SockProtocol, SockType, getsockopt, setsockopt, socket, sockopt}; +use nix::sys::socket::{socket, sockopt, getsockopt, setsockopt, AddressFamily, SockType, SockFlag, SockProtocol}; +#[cfg(not(all(target_os = "linux", + target_env = "gnu", + any(target_arch = "mips", + target_arch = "mips64", + target_arch = "aarch64", + target_arch = "arm", + target_arch = "powerpc64"))))] +use nix::{ifaddrs::getifaddrs, sys::socket::{IpAddr, IpMulticastIfInAddr, SockAddr}}; + #[cfg(any(target_os = "android", target_os = "linux"))] use crate::*; From 31c42a08e9aa5cb85153f394c31df2e5516cc8ed Mon Sep 17 00:00:00 2001 From: Han Xu Date: Thu, 24 Dec 2020 08:42:20 -0800 Subject: [PATCH 7/7] update comments --- src/sys/socket/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 7d0d808715..8cd7cbb141 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -385,8 +385,9 @@ cfg_if! { target_arch = "powerpc64"))))] { /// Request for multicast socket's outgoing interface /// - /// The value must be a `libc::in_addr` structure, which is the most common. - /// `ip_mreqn` or `ip_mreq` structure are not supported. One reason is that + /// The value is a `libc::in_addr` structure, which is the most common. + /// `ip_mreqn` or `ip_mreq` structure are not supported at this point, one + /// reason is that if we use enum to represent all possible structures, /// `#[repr(transparent)]` does not support enum. #[repr(transparent)] #[derive(Clone, Copy, Debug, Eq, PartialEq)]