Skip to content

Commit e9bb301

Browse files
committed
refactor(quinn-udp): split fast&slow send/recv paths
Separate the fast path (`msghdr_x`-based) and slow path (`msghdr`-based) implementations to prepare for runtime dispatch between them. Broken out of quinn-rs#2463 as suggested by @djc.
1 parent 4de6d2c commit e9bb301

File tree

1 file changed

+89
-6
lines changed

1 file changed

+89
-6
lines changed

quinn-udp/src/unix.rs

Lines changed: 89 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ fn send(state: &UdpSocketState, io: SockRef<'_>, transmit: &Transmit<'_>) -> io:
401401
.enumerate()
402402
.take(BATCH_SIZE)
403403
{
404-
prepare_msg(
404+
prepare_msg_x(
405405
&Transmit {
406406
destination: transmit.destination,
407407
ecn: transmit.ecn,
@@ -437,6 +437,15 @@ fn send(state: &UdpSocketState, io: SockRef<'_>, transmit: &Transmit<'_>) -> io:
437437

438438
#[cfg(any(target_os = "openbsd", target_os = "netbsd", apple_slow))]
439439
fn send(state: &UdpSocketState, io: SockRef<'_>, transmit: &Transmit<'_>) -> io::Result<()> {
440+
send_single(state, io, transmit)
441+
}
442+
443+
#[cfg(any(target_os = "openbsd", target_os = "netbsd", apple))]
444+
fn send_single(
445+
state: &UdpSocketState,
446+
io: SockRef<'_>,
447+
transmit: &Transmit<'_>,
448+
) -> io::Result<()> {
440449
let mut hdr: libc::msghdr = unsafe { mem::zeroed() };
441450
let mut iov: libc::iovec = unsafe { mem::zeroed() };
442451
let mut ctrl = cmsg::Aligned([0u8; CMSG_LEN]);
@@ -527,7 +536,7 @@ fn recv(io: SockRef<'_>, bufs: &mut [IoSliceMut<'_>], meta: &mut [RecvMeta]) ->
527536
let mut hdrs = unsafe { mem::zeroed::<[msghdr_x; BATCH_SIZE]>() };
528537
let max_msg_count = bufs.len().min(BATCH_SIZE);
529538
for i in 0..max_msg_count {
530-
prepare_recv(&mut bufs[i], &mut names[i], &mut ctrls[i], &mut hdrs[i]);
539+
prepare_recv_x(&mut bufs[i], &mut names[i], &mut ctrls[i], &mut hdrs[i]);
531540
}
532541
let msg_count = loop {
533542
let n = unsafe { recvmsg_x(io.as_raw_fd(), hdrs.as_mut_ptr(), max_msg_count as _, 0) };
@@ -557,6 +566,21 @@ fn recv(io: SockRef<'_>, bufs: &mut [IoSliceMut<'_>], meta: &mut [RecvMeta]) ->
557566
apple_slow
558567
))]
559568
fn recv(io: SockRef<'_>, bufs: &mut [IoSliceMut<'_>], meta: &mut [RecvMeta]) -> io::Result<usize> {
569+
recv_single(io, bufs, meta)
570+
}
571+
572+
#[cfg(any(
573+
target_os = "openbsd",
574+
target_os = "netbsd",
575+
target_os = "dragonfly",
576+
solarish,
577+
apple
578+
))]
579+
fn recv_single(
580+
io: SockRef<'_>,
581+
bufs: &mut [IoSliceMut<'_>],
582+
meta: &mut [RecvMeta],
583+
) -> io::Result<usize> {
560584
let mut name = MaybeUninit::<libc::sockaddr_storage>::uninit();
561585
let mut ctrl = cmsg::Aligned(MaybeUninit::<[u8; CMSG_LEN]>::uninit());
562586
let mut hdr = unsafe { mem::zeroed::<libc::msghdr>() };
@@ -588,8 +612,7 @@ const CMSG_LEN: usize = 88;
588612
fn prepare_msg(
589613
transmit: &Transmit<'_>,
590614
dst_addr: &socket2::SockAddr,
591-
#[cfg(not(apple_fast))] hdr: &mut libc::msghdr,
592-
#[cfg(apple_fast)] hdr: &mut msghdr_x,
615+
hdr: &mut libc::msghdr,
593616
iov: &mut libc::iovec,
594617
ctrl: &mut cmsg::Aligned<[u8; CMSG_LEN]>,
595618
#[allow(unused_variables)] // only used on FreeBSD & macOS
@@ -679,7 +702,66 @@ fn prepare_msg(
679702
encoder.finish();
680703
}
681704

682-
#[cfg(not(apple_fast))]
705+
/// Prepares an `msghdr_x` for use with `sendmsg_x`.
706+
#[cfg(apple_fast)]
707+
fn prepare_msg_x(
708+
transmit: &Transmit<'_>,
709+
dst_addr: &socket2::SockAddr,
710+
hdr: &mut msghdr_x,
711+
iov: &mut libc::iovec,
712+
ctrl: &mut cmsg::Aligned<[u8; CMSG_LEN]>,
713+
#[allow(unused_variables)] encode_src_ip: bool,
714+
sendmsg_einval: bool,
715+
) {
716+
iov.iov_base = transmit.contents.as_ptr() as *const _ as *mut _;
717+
iov.iov_len = transmit.contents.len();
718+
719+
let name = dst_addr.as_ptr() as *mut libc::c_void;
720+
let namelen = dst_addr.len();
721+
hdr.msg_name = name as *mut _;
722+
hdr.msg_namelen = namelen;
723+
hdr.msg_iov = iov;
724+
hdr.msg_iovlen = 1;
725+
726+
hdr.msg_control = ctrl.0.as_mut_ptr() as _;
727+
hdr.msg_controllen = CMSG_LEN as _;
728+
let mut encoder = unsafe { cmsg::Encoder::new(hdr) };
729+
let ecn = transmit.ecn.map_or(0, |x| x as libc::c_int);
730+
let is_ipv4 = transmit.destination.is_ipv4()
731+
|| matches!(transmit.destination.ip(), IpAddr::V6(addr) if addr.to_ipv4_mapped().is_some());
732+
if is_ipv4 {
733+
if !sendmsg_einval {
734+
encoder.push(libc::IPPROTO_IP, libc::IP_TOS, ecn as IpTosTy);
735+
}
736+
} else {
737+
encoder.push(libc::IPPROTO_IPV6, libc::IPV6_TCLASS, ecn);
738+
}
739+
740+
if let Some(ip) = &transmit.src_ip {
741+
match ip {
742+
IpAddr::V4(v4) => {
743+
if encode_src_ip {
744+
let addr = libc::in_addr {
745+
s_addr: u32::from_ne_bytes(v4.octets()),
746+
};
747+
encoder.push(libc::IPPROTO_IP, libc::IP_RECVDSTADDR, addr);
748+
}
749+
}
750+
IpAddr::V6(v6) => {
751+
let pktinfo = libc::in6_pktinfo {
752+
ipi6_ifindex: 0,
753+
ipi6_addr: libc::in6_addr {
754+
s6_addr: v6.octets(),
755+
},
756+
};
757+
encoder.push(libc::IPPROTO_IPV6, libc::IPV6_PKTINFO, pktinfo);
758+
}
759+
}
760+
}
761+
762+
encoder.finish();
763+
}
764+
683765
fn prepare_recv(
684766
buf: &mut IoSliceMut,
685767
name: &mut MaybeUninit<libc::sockaddr_storage>,
@@ -695,8 +777,9 @@ fn prepare_recv(
695777
hdr.msg_flags = 0;
696778
}
697779

780+
/// Prepares an `msghdr_x` for receiving with `recvmsg_x`.
698781
#[cfg(apple_fast)]
699-
fn prepare_recv(
782+
fn prepare_recv_x(
700783
buf: &mut IoSliceMut,
701784
name: &mut MaybeUninit<libc::sockaddr_storage>,
702785
ctrl: &mut cmsg::Aligned<[u8; CMSG_LEN]>,

0 commit comments

Comments
 (0)