refactor(quinn-udp): extract ControlMetadata helper

This commit is contained in:
Lars Eggert
2025-12-09 16:08:47 +02:00
committed by Dirkjan Ochtman
parent 42de9dd2be
commit 4742a70e33
+40 -24
View File
@@ -707,17 +707,42 @@ fn decode_recv<M: cmsg::MsgHdr<ControlMessage = libc::cmsghdr>>(
len: usize,
) -> io::Result<RecvMeta> {
let name = unsafe { name.assume_init() };
let mut ecn_bits = 0;
let mut dst_ip = None;
let mut interface_index = None;
#[allow(unused_mut)] // only mutable on Linux
let mut stride = len;
let mut ctrl = ControlMetadata {
ecn_bits: 0,
dst_ip: None,
interface_index: None,
stride: len,
};
let cmsg_iter = unsafe { cmsg::Iter::new(hdr) };
for cmsg in cmsg_iter {
ctrl.decode(cmsg);
}
Ok(RecvMeta {
len,
stride: ctrl.stride,
addr: decode_socket_addr(&name)?,
ecn: EcnCodepoint::from_bits(ctrl.ecn_bits),
dst_ip: ctrl.dst_ip,
interface_index: ctrl.interface_index,
})
}
/// Metadata decoded from control messages
struct ControlMetadata {
ecn_bits: u8,
dst_ip: Option<IpAddr>,
interface_index: Option<u32>,
stride: usize,
}
impl ControlMetadata {
/// Decodes a control message and updates the metadata state
fn decode(&mut self, cmsg: &libc::cmsghdr) {
match (cmsg.cmsg_level, cmsg.cmsg_type) {
(libc::IPPROTO_IP, libc::IP_TOS) => unsafe {
ecn_bits = cmsg::decode::<u8, libc::cmsghdr>(cmsg);
self.ecn_bits = cmsg::decode::<u8, libc::cmsghdr>(cmsg);
},
// FreeBSD uses IP_RECVTOS here, and we can be liberal because cmsgs are opt-in.
#[cfg(not(any(
@@ -727,7 +752,7 @@ fn decode_recv<M: cmsg::MsgHdr<ControlMessage = libc::cmsghdr>>(
solarish
)))]
(libc::IPPROTO_IP, libc::IP_RECVTOS) => unsafe {
ecn_bits = cmsg::decode::<u8, libc::cmsghdr>(cmsg);
self.ecn_bits = cmsg::decode::<u8, libc::cmsghdr>(cmsg);
},
(libc::IPPROTO_IPV6, libc::IPV6_TCLASS) => unsafe {
// Temporary hack around broken macos ABI. Remove once upstream fixes it.
@@ -736,45 +761,36 @@ fn decode_recv<M: cmsg::MsgHdr<ControlMessage = libc::cmsghdr>>(
if cfg!(apple)
&& cmsg.cmsg_len as usize == libc::CMSG_LEN(mem::size_of::<u8>() as _) as usize
{
ecn_bits = cmsg::decode::<u8, libc::cmsghdr>(cmsg);
self.ecn_bits = cmsg::decode::<u8, libc::cmsghdr>(cmsg);
} else {
ecn_bits = cmsg::decode::<libc::c_int, libc::cmsghdr>(cmsg) as u8;
self.ecn_bits = cmsg::decode::<libc::c_int, libc::cmsghdr>(cmsg) as u8;
}
},
#[cfg(any(target_os = "linux", target_os = "android"))]
(libc::IPPROTO_IP, libc::IP_PKTINFO) => {
let pktinfo = unsafe { cmsg::decode::<libc::in_pktinfo, libc::cmsghdr>(cmsg) };
dst_ip = Some(IpAddr::V4(Ipv4Addr::from(
self.dst_ip = Some(IpAddr::V4(Ipv4Addr::from(
pktinfo.ipi_addr.s_addr.to_ne_bytes(),
)));
interface_index = Some(pktinfo.ipi_ifindex as u32);
self.interface_index = Some(pktinfo.ipi_ifindex as u32);
}
#[cfg(any(bsd, apple))]
(libc::IPPROTO_IP, libc::IP_RECVDSTADDR) => {
let in_addr = unsafe { cmsg::decode::<libc::in_addr, libc::cmsghdr>(cmsg) };
dst_ip = Some(IpAddr::V4(Ipv4Addr::from(in_addr.s_addr.to_ne_bytes())));
self.dst_ip = Some(IpAddr::V4(Ipv4Addr::from(in_addr.s_addr.to_ne_bytes())));
}
(libc::IPPROTO_IPV6, libc::IPV6_PKTINFO) => {
let pktinfo = unsafe { cmsg::decode::<libc::in6_pktinfo, libc::cmsghdr>(cmsg) };
dst_ip = Some(IpAddr::V6(Ipv6Addr::from(pktinfo.ipi6_addr.s6_addr)));
interface_index = Some(pktinfo.ipi6_ifindex as u32);
self.dst_ip = Some(IpAddr::V6(Ipv6Addr::from(pktinfo.ipi6_addr.s6_addr)));
self.interface_index = Some(pktinfo.ipi6_ifindex as u32);
}
#[cfg(any(target_os = "linux", target_os = "android"))]
(libc::SOL_UDP, libc::UDP_GRO) => unsafe {
stride = cmsg::decode::<libc::c_int, libc::cmsghdr>(cmsg) as usize;
self.stride = cmsg::decode::<libc::c_int, libc::cmsghdr>(cmsg) as usize;
},
_ => {}
}
}
Ok(RecvMeta {
len,
stride,
addr: decode_socket_addr(&name)?,
ecn: EcnCodepoint::from_bits(ecn_bits),
dst_ip,
interface_index,
})
}
/// Decodes a `sockaddr_storage` into a `SocketAddr`