@@ -80,6 +80,13 @@ use crate::{Domain, Protocol, SockAddr, TcpKeepalive, Type};
8080#[ cfg( not( target_os = "redox" ) ) ]
8181use crate :: { MsgHdr , MsgHdrMut , RecvFlags } ;
8282
83+ define_mmsg_if_supported ! {
84+ use crate :: { MMsgHdr , MMsgHdrMut } ;
85+
86+ // Used in `MMsgHdr`.
87+ pub ( crate ) use libc:: mmsghdr;
88+ }
89+
8390pub ( crate ) use libc:: c_int;
8491
8592// Used in `Domain`.
@@ -1076,6 +1083,37 @@ pub(crate) fn recvmsg(
10761083 syscall ! ( recvmsg( fd, & mut msg. inner, flags) ) . map ( |n| n as usize )
10771084}
10781085
1086+ define_mmsg_if_supported ! {
1087+ pub ( crate ) fn recvmmsg(
1088+ fd: Socket ,
1089+ msgvec: & mut [ MMsgHdrMut <' _, ' _, ' _>] ,
1090+ flags: c_int,
1091+ timeout: Option <Duration >,
1092+ ) -> io:: Result <usize > {
1093+ if cfg!( target_env = "musl" ) {
1094+ debug_assert!( flags >= 0 , "socket flags must be non-negative" ) ;
1095+ }
1096+
1097+ let mut timeout = timeout. map( into_timespec) ;
1098+ let timeout_ptr = timeout
1099+ . as_mut( )
1100+ . map( |t| t as * mut _)
1101+ . unwrap_or( ptr:: null_mut( ) ) ;
1102+
1103+ syscall!( recvmmsg(
1104+ fd,
1105+ // SAFETY: `MMsgHdrMut` is `#[repr(transparent)]` and wraps a `libc::mmsghdr`
1106+ msgvec. as_mut_ptr( ) as * mut mmsghdr,
1107+ msgvec. len( ) as _,
1108+ // On glibc: `c_int` to `c_int` (no change).
1109+ // On musl: `c_int` to `c_uint`.
1110+ flags as _,
1111+ timeout_ptr
1112+ ) )
1113+ . map( |n| n as usize )
1114+ }
1115+ }
1116+
10791117pub ( crate ) fn send ( fd : Socket , buf : & [ u8 ] , flags : c_int ) -> io:: Result < usize > {
10801118 syscall ! ( send(
10811119 fd,
@@ -1120,6 +1158,29 @@ pub(crate) fn sendmsg(fd: Socket, msg: &MsgHdr<'_, '_, '_>, flags: c_int) -> io:
11201158 syscall ! ( sendmsg( fd, & msg. inner, flags) ) . map ( |n| n as usize )
11211159}
11221160
1161+ define_mmsg_if_supported ! {
1162+ pub ( crate ) fn sendmmsg(
1163+ fd: Socket ,
1164+ msgvec: & mut [ MMsgHdr <' _, ' _, ' _>] ,
1165+ flags: c_int,
1166+ ) -> io:: Result <usize > {
1167+ if cfg!( target_env = "musl" ) {
1168+ debug_assert!( flags >= 0 , "socket flags must be non-negative" ) ;
1169+ }
1170+
1171+ syscall!( sendmmsg(
1172+ fd,
1173+ // SAFETY: `MMsgHdr` is `#[repr(transparent)]` and wraps a `libc::mmsghdr`
1174+ msgvec. as_mut_ptr( ) as * mut mmsghdr,
1175+ msgvec. len( ) as _,
1176+ // On glibc: `c_int` to `c_int` (no change).
1177+ // On musl: `c_int` to `c_uint`.
1178+ flags as _
1179+ ) )
1180+ . map( |n| n as usize )
1181+ }
1182+ }
1183+
11231184/// Wrapper around `getsockopt` to deal with platform specific timeouts.
11241185pub ( crate ) fn timeout_opt ( fd : Socket , opt : c_int , val : c_int ) -> io:: Result < Option < Duration > > {
11251186 unsafe { getsockopt ( fd, opt, val) . map ( from_timeval) }
@@ -1161,6 +1222,26 @@ fn into_timeval(duration: Option<Duration>) -> libc::timeval {
11611222 }
11621223}
11631224
1225+ #[ allow( dead_code) ] // Used by `recvmmsg()`.
1226+ fn into_timespec ( duration : Duration ) -> libc:: timespec {
1227+ // https://github.com/rust-lang/libc/issues/1848
1228+ #[ cfg_attr( target_env = "musl" , allow( deprecated) ) ]
1229+ libc:: timespec {
1230+ tv_sec : min ( duration. as_secs ( ) , libc:: time_t:: MAX as u64 ) as libc:: time_t ,
1231+ #[ cfg( any(
1232+ all( target_arch = "x86_64" , target_pointer_width = "32" ) ,
1233+ target_pointer_width = "64"
1234+ ) ) ]
1235+ tv_nsec : duration. subsec_nanos ( ) as i64 ,
1236+
1237+ #[ cfg( not( any(
1238+ all( target_arch = "x86_64" , target_pointer_width = "32" ) ,
1239+ target_pointer_width = "64"
1240+ ) ) ) ]
1241+ tv_nsec : duration. subsec_nanos ( ) . clamp ( 0 , i32:: MAX as u32 ) as i32 ,
1242+ }
1243+ }
1244+
11641245#[ cfg( all(
11651246 feature = "all" ,
11661247 not( any( target_os = "haiku" , target_os = "openbsd" , target_os = "vita" ) )
0 commit comments