@@ -397,7 +397,7 @@ fn send(state: &UdpSocketState, io: SockRef<'_>, transmit: &Transmit<'_>) -> io:
397397 . enumerate ( )
398398 . take ( BATCH_SIZE )
399399 {
400- prepare_msg (
400+ prepare_msg_x (
401401 & Transmit {
402402 destination : transmit. destination ,
403403 ecn : transmit. ecn ,
@@ -433,6 +433,12 @@ fn send(state: &UdpSocketState, io: SockRef<'_>, transmit: &Transmit<'_>) -> io:
433433
434434#[ cfg( any( target_os = "openbsd" , target_os = "netbsd" , apple_slow) ) ]
435435fn send ( state : & UdpSocketState , io : SockRef < ' _ > , transmit : & Transmit < ' _ > ) -> io:: Result < ( ) > {
436+ send_single ( state, io, transmit)
437+ }
438+
439+ #[ cfg( any( target_os = "openbsd" , target_os = "netbsd" , apple) ) ]
440+ #[ cfg_attr( apple_fast, allow( dead_code) ) ] // Unused when apple_fast is enabled
441+ fn send_single ( state : & UdpSocketState , io : SockRef < ' _ > , transmit : & Transmit < ' _ > ) -> io:: Result < ( ) > {
436442 let mut hdr: libc:: msghdr = unsafe { mem:: zeroed ( ) } ;
437443 let mut iov: libc:: iovec = unsafe { mem:: zeroed ( ) } ;
438444 let mut ctrl = cmsg:: Aligned ( [ 0u8 ; CMSG_LEN ] ) ;
@@ -523,7 +529,7 @@ fn recv(io: SockRef<'_>, bufs: &mut [IoSliceMut<'_>], meta: &mut [RecvMeta]) ->
523529 let mut hdrs = unsafe { mem:: zeroed :: < [ msghdr_x ; BATCH_SIZE ] > ( ) } ;
524530 let max_msg_count = bufs. len ( ) . min ( BATCH_SIZE ) ;
525531 for i in 0 ..max_msg_count {
526- prepare_recv ( & mut bufs[ i] , & mut names[ i] , & mut ctrls[ i] , & mut hdrs[ i] ) ;
532+ prepare_recv_x ( & mut bufs[ i] , & mut names[ i] , & mut ctrls[ i] , & mut hdrs[ i] ) ;
527533 }
528534 let msg_count = loop {
529535 let n = unsafe { recvmsg_x ( io. as_raw_fd ( ) , hdrs. as_mut_ptr ( ) , max_msg_count as _ , 0 ) } ;
@@ -553,6 +559,22 @@ fn recv(io: SockRef<'_>, bufs: &mut [IoSliceMut<'_>], meta: &mut [RecvMeta]) ->
553559 apple_slow
554560) ) ]
555561fn recv ( io : SockRef < ' _ > , bufs : & mut [ IoSliceMut < ' _ > ] , meta : & mut [ RecvMeta ] ) -> io:: Result < usize > {
562+ recv_single ( io, bufs, meta)
563+ }
564+
565+ #[ cfg( any(
566+ target_os = "openbsd" ,
567+ target_os = "netbsd" ,
568+ target_os = "dragonfly" ,
569+ solarish,
570+ apple
571+ ) ) ]
572+ #[ cfg_attr( apple_fast, allow( dead_code) ) ] // Unused when apple_fast is enabled
573+ fn recv_single (
574+ io : SockRef < ' _ > ,
575+ bufs : & mut [ IoSliceMut < ' _ > ] ,
576+ meta : & mut [ RecvMeta ] ,
577+ ) -> io:: Result < usize > {
556578 let mut name = MaybeUninit :: < libc:: sockaddr_storage > :: uninit ( ) ;
557579 let mut ctrl = cmsg:: Aligned ( MaybeUninit :: < [ u8 ; CMSG_LEN ] > :: uninit ( ) ) ;
558580 let mut hdr = unsafe { mem:: zeroed :: < libc:: msghdr > ( ) } ;
@@ -581,11 +603,11 @@ fn recv(io: SockRef<'_>, bufs: &mut [IoSliceMut<'_>], meta: &mut [RecvMeta]) ->
581603
582604const CMSG_LEN : usize = 88 ;
583605
606+ #[ cfg_attr( apple_fast, allow( dead_code) ) ] // Unused when apple_fast is enabled
584607fn prepare_msg (
585608 transmit : & Transmit < ' _ > ,
586609 dst_addr : & socket2:: SockAddr ,
587- #[ cfg( not( apple_fast) ) ] hdr : & mut libc:: msghdr ,
588- #[ cfg( apple_fast) ] hdr : & mut msghdr_x ,
610+ hdr : & mut libc:: msghdr ,
589611 iov : & mut libc:: iovec ,
590612 ctrl : & mut cmsg:: Aligned < [ u8 ; CMSG_LEN ] > ,
591613 #[ allow( unused_variables) ] // only used on FreeBSD & macOS
@@ -625,6 +647,10 @@ fn prepare_msg(
625647 encoder. push ( libc:: IPPROTO_IPV6 , libc:: IPV6_TCLASS , ecn) ;
626648 }
627649
650+ // On apple_fast, prepare_msg is only compiled for send_single (fallback path), while the main
651+ // send path uses prepare_msg_x with msghdr_x. gso::set_segment_size has a different signature
652+ // when apple_fast is enabled, and it's a no-op on non-Linux platforms anyway.
653+ #[ cfg( not( apple_fast) ) ]
628654 if let Some ( segment_size) = transmit. effective_segment_size ( ) {
629655 gso:: set_segment_size ( & mut encoder, segment_size as u16 ) ;
630656 }
@@ -668,7 +694,67 @@ fn prepare_msg(
668694 encoder. finish ( ) ;
669695}
670696
671- #[ cfg( not( apple_fast) ) ]
697+ /// Prepares an `msghdr_x` for use with `sendmsg_x`.
698+ #[ cfg( apple_fast) ]
699+ fn prepare_msg_x (
700+ transmit : & Transmit < ' _ > ,
701+ dst_addr : & socket2:: SockAddr ,
702+ hdr : & mut msghdr_x ,
703+ iov : & mut libc:: iovec ,
704+ ctrl : & mut cmsg:: Aligned < [ u8 ; CMSG_LEN ] > ,
705+ #[ allow( unused_variables) ] encode_src_ip : bool ,
706+ sendmsg_einval : bool ,
707+ ) {
708+ iov. iov_base = transmit. contents . as_ptr ( ) as * const _ as * mut _ ;
709+ iov. iov_len = transmit. contents . len ( ) ;
710+
711+ let name = dst_addr. as_ptr ( ) as * mut libc:: c_void ;
712+ let namelen = dst_addr. len ( ) ;
713+ hdr. msg_name = name as * mut _ ;
714+ hdr. msg_namelen = namelen;
715+ hdr. msg_iov = iov;
716+ hdr. msg_iovlen = 1 ;
717+
718+ hdr. msg_control = ctrl. 0 . as_mut_ptr ( ) as _ ;
719+ hdr. msg_controllen = CMSG_LEN as _ ;
720+ let mut encoder = unsafe { cmsg:: Encoder :: new ( hdr) } ;
721+ let ecn = transmit. ecn . map_or ( 0 , |x| x as libc:: c_int ) ;
722+ let is_ipv4 = transmit. destination . is_ipv4 ( )
723+ || matches ! ( transmit. destination. ip( ) , IpAddr :: V6 ( addr) if addr. to_ipv4_mapped( ) . is_some( ) ) ;
724+ if is_ipv4 {
725+ if !sendmsg_einval {
726+ encoder. push ( libc:: IPPROTO_IP , libc:: IP_TOS , ecn as IpTosTy ) ;
727+ }
728+ } else {
729+ encoder. push ( libc:: IPPROTO_IPV6 , libc:: IPV6_TCLASS , ecn) ;
730+ }
731+
732+ if let Some ( ip) = & transmit. src_ip {
733+ match ip {
734+ IpAddr :: V4 ( v4) => {
735+ if encode_src_ip {
736+ let addr = libc:: in_addr {
737+ s_addr : u32:: from_ne_bytes ( v4. octets ( ) ) ,
738+ } ;
739+ encoder. push ( libc:: IPPROTO_IP , libc:: IP_RECVDSTADDR , addr) ;
740+ }
741+ }
742+ IpAddr :: V6 ( v6) => {
743+ let pktinfo = libc:: in6_pktinfo {
744+ ipi6_ifindex : 0 ,
745+ ipi6_addr : libc:: in6_addr {
746+ s6_addr : v6. octets ( ) ,
747+ } ,
748+ } ;
749+ encoder. push ( libc:: IPPROTO_IPV6 , libc:: IPV6_PKTINFO , pktinfo) ;
750+ }
751+ }
752+ }
753+
754+ encoder. finish ( ) ;
755+ }
756+
757+ #[ cfg_attr( apple_fast, allow( dead_code) ) ] // Unused when apple_fast is enabled
672758fn prepare_recv (
673759 buf : & mut IoSliceMut < ' _ > ,
674760 name : & mut MaybeUninit < libc:: sockaddr_storage > ,
@@ -684,8 +770,9 @@ fn prepare_recv(
684770 hdr. msg_flags = 0 ;
685771}
686772
773+ /// Prepares an `msghdr_x` for receiving with `recvmsg_x`.
687774#[ cfg( apple_fast) ]
688- fn prepare_recv (
775+ fn prepare_recv_x (
689776 buf : & mut IoSliceMut < ' _ > ,
690777 name : & mut MaybeUninit < libc:: sockaddr_storage > ,
691778 ctrl : & mut cmsg:: Aligned < [ u8 ; CMSG_LEN ] > ,
@@ -1006,6 +1093,7 @@ mod gso {
10061093 }
10071094 }
10081095
1096+ #[ cfg_attr( apple_fast, allow( dead_code) ) ] // Unused when apple_fast is enabled
10091097 pub ( super ) fn set_segment_size (
10101098 #[ cfg( not( apple_fast) ) ] _encoder : & mut cmsg:: Encoder < ' _ , libc:: msghdr > ,
10111099 #[ cfg( apple_fast) ] _encoder : & mut cmsg:: Encoder < ' _ , msghdr_x > ,
0 commit comments