Extract Unix recv setup/decode logic into functions

This commit is contained in:
Benjamin Saunders
2020-10-31 17:49:15 -07:00
committed by Dirkjan Ochtman
parent 7efb56a4eb
commit b9f1d2803f
+56 -40
View File
@@ -171,13 +171,7 @@ impl super::UdpExt for UdpSocket {
let mut name = MaybeUninit::<libc::sockaddr_storage>::uninit();
let mut ctrl = cmsg::Aligned(MaybeUninit::<[u8; CMSG_LEN]>::uninit());
let mut hdr = unsafe { mem::zeroed::<libc::msghdr>() };
hdr.msg_name = name.as_mut_ptr() as _;
hdr.msg_namelen = mem::size_of::<libc::sockaddr_storage>() as _;
hdr.msg_iov = &mut bufs[0] as *mut IoSliceMut as *mut libc::iovec;
hdr.msg_iovlen = 1;
hdr.msg_control = ctrl.0.as_mut_ptr() as _;
hdr.msg_controllen = CMSG_LEN as _;
hdr.msg_flags = 0;
prepare_recv(&mut bufs[0], &mut name, &mut ctrl, &mut hdr);
let n = loop {
let n = unsafe { libc::recvmsg(self.as_raw_fd(), &mut hdr, 0) };
if n == -1 {
@@ -192,39 +186,7 @@ impl super::UdpExt for UdpSocket {
}
break n;
};
let name = unsafe { name.assume_init() };
let ecn_bits = match unsafe { cmsg::Iter::new(&hdr).next() } {
Some(cmsg) => match (cmsg.cmsg_level, cmsg.cmsg_type) {
// FreeBSD uses IP_RECVTOS here, and we can be liberal because cmsgs are opt-in.
(libc::IPPROTO_IP, libc::IP_TOS) | (libc::IPPROTO_IP, libc::IP_RECVTOS) => unsafe {
cmsg::decode::<u8>(cmsg)
},
(libc::IPPROTO_IPV6, libc::IPV6_TCLASS) => unsafe {
// Temporary hack around broken macos ABI. Remove once upstream fixes it.
// https://bugreport.apple.com/web/?problemID=48761855
if cfg!(target_os = "macos")
&& cmsg.cmsg_len as usize
== libc::CMSG_LEN(mem::size_of::<u8>() as _) as usize
{
cmsg::decode::<u8>(cmsg)
} else {
cmsg::decode::<libc::c_int>(cmsg) as u8
}
},
_ => 0,
},
None => 0,
};
let addr = match libc::c_int::from(name.ss_family) {
libc::AF_INET => unsafe { SocketAddr::V4(ptr::read(&name as *const _ as _)) },
libc::AF_INET6 => unsafe { SocketAddr::V6(ptr::read(&name as *const _ as _)) },
_ => unreachable!(),
};
meta[0] = RecvMeta {
len: n as usize,
addr,
ecn: EcnCodepoint::from_bits(ecn_bits),
};
meta[0] = decode_recv(&name, &hdr, n as usize);
Ok(1)
}
}
@@ -260,3 +222,57 @@ fn prepare_msg(
}
encoder.finish();
}
fn prepare_recv(
buf: &mut IoSliceMut,
name: &mut MaybeUninit<libc::sockaddr_storage>,
ctrl: &mut cmsg::Aligned<MaybeUninit<[u8; CMSG_LEN]>>,
hdr: &mut libc::msghdr,
) {
hdr.msg_name = name.as_mut_ptr() as _;
hdr.msg_namelen = mem::size_of::<libc::sockaddr_storage>() as _;
hdr.msg_iov = buf as *mut IoSliceMut as *mut libc::iovec;
hdr.msg_iovlen = 1;
hdr.msg_control = ctrl.0.as_mut_ptr() as _;
hdr.msg_controllen = CMSG_LEN as _;
hdr.msg_flags = 0;
}
fn decode_recv(
name: &MaybeUninit<libc::sockaddr_storage>,
hdr: &libc::msghdr,
len: usize,
) -> RecvMeta {
let name = unsafe { name.assume_init() };
let ecn_bits = match unsafe { cmsg::Iter::new(&hdr).next() } {
Some(cmsg) => match (cmsg.cmsg_level, cmsg.cmsg_type) {
// FreeBSD uses IP_RECVTOS here, and we can be liberal because cmsgs are opt-in.
(libc::IPPROTO_IP, libc::IP_TOS) | (libc::IPPROTO_IP, libc::IP_RECVTOS) => unsafe {
cmsg::decode::<u8>(cmsg)
},
(libc::IPPROTO_IPV6, libc::IPV6_TCLASS) => unsafe {
// Temporary hack around broken macos ABI. Remove once upstream fixes it.
// https://bugreport.apple.com/web/?problemID=48761855
if cfg!(target_os = "macos")
&& cmsg.cmsg_len as usize == libc::CMSG_LEN(mem::size_of::<u8>() as _) as usize
{
cmsg::decode::<u8>(cmsg)
} else {
cmsg::decode::<libc::c_int>(cmsg) as u8
}
},
_ => 0,
},
None => 0,
};
let addr = match libc::c_int::from(name.ss_family) {
libc::AF_INET => unsafe { SocketAddr::V4(ptr::read(&name as *const _ as _)) },
libc::AF_INET6 => unsafe { SocketAddr::V6(ptr::read(&name as *const _ as _)) },
_ => unreachable!(),
};
RecvMeta {
len,
addr,
ecn: EcnCodepoint::from_bits(ecn_bits),
}
}