@@ -80,6 +80,13 @@ use crate::{Domain, Protocol, SockAddr, TcpKeepalive, Type};
8080#[ cfg( not( target_os = "redox" ) ) ]
8181use crate :: { MsgHdr , MsgHdrMut , RecvFlags } ;
8282
83+ #[ cfg( all( feature = "all" , any( target_os = "linux" , target_os = "android" , ) ) ) ]
84+ use crate :: { MMsgHdr , MMsgHdrMut } ;
85+
86+ // Used in `MMsgHdr`.
87+ #[ cfg( any( target_os = "linux" , target_os = "android" , ) ) ]
88+ pub ( crate ) use libc:: mmsghdr;
89+
8390pub ( crate ) use libc:: c_int;
8491
8592// Used in `Domain`.
@@ -1076,6 +1083,35 @@ pub(crate) fn recvmsg(
10761083 syscall ! ( recvmsg( fd, & mut msg. inner, flags) ) . map ( |n| n as usize )
10771084}
10781085
1086+ #[ cfg( all( feature = "all" , any( target_os = "linux" , target_os = "android" , ) ) ) ]
1087+ /// This emits all the messages in a single syscall
1088+ pub ( crate ) fn recvmmsg (
1089+ fd : Socket ,
1090+ msgvec : & mut [ MMsgHdrMut < ' _ , ' _ , ' _ > ] ,
1091+ flags : c_int ,
1092+ timeout : Option < Duration > ,
1093+ ) -> io:: Result < usize > {
1094+ if cfg ! ( target_env = "musl" ) {
1095+ debug_assert ! ( flags >= 0 , "socket flags must be non-negative" ) ;
1096+ }
1097+
1098+ let mut timeout = timeout. map ( into_timespec) ;
1099+ let timeout_ptr = timeout
1100+ . as_mut ( )
1101+ . map ( |t| t as * mut _ )
1102+ . unwrap_or ( ptr:: null_mut ( ) ) ;
1103+
1104+ syscall ! ( recvmmsg(
1105+ fd,
1106+ // SAFETY: `MMsgHdrMut` is `#[repr(transparent)]` and wraps a `libc::mmsghdr`
1107+ msgvec. as_mut_ptr( ) as * mut mmsghdr,
1108+ msgvec. len( ) as _,
1109+ flags as _,
1110+ timeout_ptr
1111+ ) )
1112+ . map ( |n| n as usize )
1113+ }
1114+
10791115pub ( crate ) fn send ( fd : Socket , buf : & [ u8 ] , flags : c_int ) -> io:: Result < usize > {
10801116 syscall ! ( send(
10811117 fd,
@@ -1120,6 +1156,27 @@ pub(crate) fn sendmsg(fd: Socket, msg: &MsgHdr<'_, '_, '_>, flags: c_int) -> io:
11201156 syscall ! ( sendmsg( fd, & msg. inner, flags) ) . map ( |n| n as usize )
11211157}
11221158
1159+ #[ cfg( all( feature = "all" , any( target_os = "linux" , target_os = "android" , ) ) ) ]
1160+ /// This transmits all the messages in a single syscall
1161+ pub ( crate ) fn sendmmsg (
1162+ fd : Socket ,
1163+ msgvec : & mut [ MMsgHdr < ' _ , ' _ , ' _ > ] ,
1164+ flags : c_int ,
1165+ ) -> io:: Result < usize > {
1166+ if cfg ! ( target_env = "musl" ) {
1167+ debug_assert ! ( flags >= 0 , "socket flags must be non-negative" ) ;
1168+ }
1169+
1170+ syscall ! ( sendmmsg(
1171+ fd,
1172+ // SAFETY: `MMsgHdr` is `#[repr(transparent)]` and wraps a `libc::mmsghdr`
1173+ msgvec. as_mut_ptr( ) as * mut mmsghdr,
1174+ msgvec. len( ) as _,
1175+ flags as _
1176+ ) )
1177+ . map ( |n| n as usize )
1178+ }
1179+
11231180/// Wrapper around `getsockopt` to deal with platform specific timeouts.
11241181pub ( crate ) fn timeout_opt ( fd : Socket , opt : c_int , val : c_int ) -> io:: Result < Option < Duration > > {
11251182 unsafe { getsockopt ( fd, opt, val) . map ( from_timeval) }
@@ -1161,6 +1218,26 @@ fn into_timeval(duration: Option<Duration>) -> libc::timeval {
11611218 }
11621219}
11631220
1221+ #[ cfg( all( feature = "all" , any( target_os = "linux" , target_os = "android" , ) ) ) ]
1222+ fn into_timespec ( duration : Duration ) -> libc:: timespec {
1223+ // https://github.com/rust-lang/libc/issues/1848
1224+ #[ cfg_attr( target_env = "musl" , allow( deprecated) ) ]
1225+ libc:: timespec {
1226+ tv_sec : min ( duration. as_secs ( ) , libc:: time_t:: MAX as u64 ) as libc:: time_t ,
1227+ #[ cfg( any(
1228+ all( target_arch = "x86_64" , target_pointer_width = "32" ) ,
1229+ target_pointer_width = "64"
1230+ ) ) ]
1231+ tv_nsec : duration. subsec_nanos ( ) as i64 ,
1232+
1233+ #[ cfg( not( any(
1234+ all( target_arch = "x86_64" , target_pointer_width = "32" ) ,
1235+ target_pointer_width = "64"
1236+ ) ) ) ]
1237+ tv_nsec : duration. subsec_nanos ( ) . clamp ( 0 , i32:: MAX as u32 ) as i32 ,
1238+ }
1239+ }
1240+
11641241#[ cfg( all(
11651242 feature = "all" ,
11661243 not( any( target_os = "haiku" , target_os = "openbsd" , target_os = "vita" ) )
0 commit comments