@@ -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