@@ -574,15 +574,20 @@ macro_rules! cmsg_space {
574
574
}
575
575
576
576
#[ derive( Clone , Copy , Debug , Eq , PartialEq ) ]
577
- pub struct RecvMsg <' a, S > {
577
+ /// Contains outcome of sending or receiving a message
578
+ ///
579
+ /// Use [`cmsgs`][RecvMsg::cmsgs] to access all the control messages present, and
580
+ /// [`iovs`][RecvMsg::iovs`] to access underlying io slices.
581
+ pub struct RecvMsg <' a, ' s, S > {
578
582
pub bytes: usize ,
579
583
cmsghdr: Option <& ' a cmsghdr>,
580
584
pub address: Option <S >,
581
585
pub flags: MsgFlags ,
586
+ iobufs: std:: marker:: PhantomData <& ' s( ) >,
582
587
mhdr: msghdr,
583
588
}
584
589
585
- impl <' a, S > RecvMsg <' a, S > {
590
+ impl <' a, S > RecvMsg <' a, ' _ , S > {
586
591
/// Iterate over the valid control messages pointed to by this
587
592
/// msghdr.
588
593
pub fn cmsgs( & self ) -> CmsgIterator {
@@ -1411,24 +1416,6 @@ pub fn sendmsg<S>(fd: RawFd, iov: &[IoSlice<'_>], cmsgs: &[ControlMessage],
1411
1416
Errno :: result( ret) . map( |r| r as usize )
1412
1417
}
1413
1418
1414
- #[ cfg( any(
1415
- target_os = "linux" ,
1416
- target_os = "android" ,
1417
- target_os = "freebsd" ,
1418
- target_os = "netbsd" ,
1419
- ) ) ]
1420
- #[ derive( Debug ) ]
1421
- pub struct SendMmsgData <' a, I , C , S >
1422
- where
1423
- I : AsRef <[ IoSlice <' a>] >,
1424
- C : AsRef <[ ControlMessage <' a>] >,
1425
- S : SockaddrLike + ' a
1426
- {
1427
- pub iov: I ,
1428
- pub cmsgs: C ,
1429
- pub addr: Option <S >,
1430
- pub _lt: std:: marker:: PhantomData <& ' a I >,
1431
- }
1432
1419
1433
1420
/// An extension of `sendmsg` that allows the caller to transmit multiple
1434
1421
/// messages on a socket using a single system call. This has performance
@@ -1453,51 +1440,66 @@ pub struct SendMmsgData<'a, I, C, S>
1453
1440
target_os = "freebsd" ,
1454
1441
target_os = "netbsd" ,
1455
1442
) ) ]
1456
- pub fn sendmmsg<' a, I , C , S >(
1443
+ pub fn sendmmsg<' a, XS , AS , C , I , S >(
1457
1444
fd: RawFd ,
1458
- data: impl std:: iter:: IntoIterator <Item =& ' a SendMmsgData <' a, I , C , S >>,
1445
+ data: & ' a mut MultHdrs <S >,
1446
+ slices: XS ,
1447
+ // one address per group of slices
1448
+ addrs: AS ,
1449
+ // shared across all the messages
1450
+ cmsgs: C ,
1459
1451
flags: MsgFlags
1460
- ) -> Result <Vec < usize >>
1452
+ ) -> crate :: Result <MultiResults < ' a , S >>
1461
1453
where
1454
+ XS : IntoIterator <Item = I >,
1455
+ AS : AsRef <[ Option <S >] >,
1462
1456
I : AsRef <[ IoSlice <' a>] > + ' a,
1463
1457
C : AsRef <[ ControlMessage <' a>] > + ' a,
1464
1458
S : SockaddrLike + ' a
1465
1459
{
1466
- let iter = data. into_iter( ) ;
1467
1460
1468
- let size_hint = iter. size_hint( ) ;
1469
- let reserve_items = size_hint. 1 . unwrap_or( size_hint. 0 ) ;
1461
+ let mut count = 0 ;
1470
1462
1471
- let mut output = Vec :: <libc:: mmsghdr>:: with_capacity( reserve_items) ;
1472
1463
1473
- let mut cmsgs_buffers = Vec :: <Vec <u8 >>:: with_capacity( reserve_items) ;
1474
-
1475
- for d in iter {
1476
- let capacity: usize = d. cmsgs. as_ref( ) . iter( ) . map( |c| c. space( ) ) . sum( ) ;
1477
- let mut cmsgs_buffer = vec![ 0u8 ; capacity] ;
1464
+ for ( i, ( ( slice, addr) , mmsghdr) ) in slices. into_iter( ) . zip( addrs. as_ref( ) ) . zip( data. items. iter_mut( ) ) . enumerate( ) {
1465
+ let mut p = & mut mmsghdr. msg_hdr;
1466
+ p. msg_iov = slice. as_ref( ) . as_ptr( ) as * mut libc:: iovec;
1467
+ p. msg_iovlen = slice. as_ref( ) . len( ) as _;
1478
1468
1479
- output. push( libc:: mmsghdr {
1480
- msg_hdr: pack_mhdr_to_send(
1481
- & mut cmsgs_buffer,
1482
- & d. iov,
1483
- & d. cmsgs,
1484
- d. addr. as_ref( )
1485
- ) ,
1486
- msg_len: 0 ,
1487
- } ) ;
1488
- cmsgs_buffers. push( cmsgs_buffer) ;
1489
- } ;
1469
+ ( * p) . msg_namelen = addr. as_ref( ) . map_or( 0 , S :: len) ;
1470
+ ( * p) . msg_name = addr. as_ref( ) . map_or( ptr:: null( ) , S :: as_ptr) as _;
1471
+
1472
+ // Encode each cmsg. This must happen after initializing the header because
1473
+ // CMSG_NEXT_HDR and friends read the msg_control and msg_controllen fields.
1474
+ // CMSG_FIRSTHDR is always safe
1475
+ let mut pmhdr: * mut cmsghdr = unsafe { CMSG_FIRSTHDR ( p) } ;
1476
+ for cmsg in cmsgs. as_ref( ) {
1477
+ assert_ne!( pmhdr, ptr:: null_mut( ) ) ;
1478
+ // Safe because we know that pmhdr is valid, and we initialized it with
1479
+ // sufficient space
1480
+ unsafe { cmsg. encode_into( pmhdr) } ;
1481
+ // Safe because mhdr is valid
1482
+ pmhdr = unsafe { CMSG_NXTHDR ( p, pmhdr) } ;
1483
+ }
1490
1484
1491
- let ret = unsafe { libc:: sendmmsg( fd, output. as_mut_ptr( ) , output. len( ) as _, flags. bits( ) as _) } ;
1485
+ count = i+1 ;
1486
+ }
1492
1487
1493
- let sent_messages = Errno :: result( ret) ? as usize ;
1494
- let mut sent_bytes = Vec :: with_capacity( sent_messages) ;
1488
+ let sent = Errno :: result( unsafe {
1489
+ libc:: sendmmsg(
1490
+ fd,
1491
+ data. items. as_mut_ptr( ) ,
1492
+ count as _,
1493
+ flags. bits( ) as _
1494
+ )
1495
+ } ) ? as usize ;
1495
1496
1496
- for item in & output {
1497
- sent_bytes. push( item. msg_len as usize ) ;
1498
- }
1497
+ Ok ( MultiResults {
1498
+ rmm: data,
1499
+ current_index: 0 ,
1500
+ received: sent
1501
+ } )
1499
1502
1500
- Ok ( sent_bytes)
1501
1503
}
1502
1504
1503
1505
@@ -1508,8 +1510,8 @@ pub fn sendmmsg<'a, I, C, S>(
1508
1510
target_os = "netbsd" ,
1509
1511
) ) ]
1510
1512
#[ derive( Debug ) ]
1511
- /// Preallocated structures needed for [`recvmmsg`] function
1512
- pub struct RecvMMsg <S > {
1513
+ /// Preallocated structures needed for [`recvmmsg`] and [`sendmmsg`] functions
1514
+ pub struct MultHdrs <S > {
1513
1515
// preallocated boxed slice of mmsghdr
1514
1516
items: Box <[ libc:: mmsghdr] >,
1515
1517
addresses: Box <[ mem:: MaybeUninit <S >] >,
@@ -1526,8 +1528,8 @@ pub struct RecvMMsg<S> {
1526
1528
target_os = "freebsd" ,
1527
1529
target_os = "netbsd" ,
1528
1530
) ) ]
1529
- impl <S > RecvMMsg <S > {
1530
- /// Preallocate structure used by [`recvmmsg`], takes number of headers to preallocate
1531
+ impl <S > MultHdrs <S > {
1532
+ /// Preallocate structure used by [`recvmmsg`] and [`sendmmsg`] takes number of headers to preallocate
1531
1533
///
1532
1534
/// `cmsg_buffer` should be created with [`cmsg_space!`] if needed
1533
1535
pub fn preallocate( num_slices: usize , cmsg_buffer: Option <Vec <u8 >>) -> Self
@@ -1598,21 +1600,21 @@ impl<S> RecvMMsg<S> {
1598
1600
) ) ]
1599
1601
pub fn recvmmsg<' a, XS , S , I >(
1600
1602
fd: RawFd ,
1601
- data: & ' a mut RecvMMsg <S >,
1603
+ data: & ' a mut MultHdrs <S >,
1602
1604
slices: XS ,
1603
1605
flags: MsgFlags ,
1604
1606
mut timeout: Option <crate :: sys:: time:: TimeSpec >,
1605
- ) -> crate :: Result <RecvMMsgItems <' a, S >>
1607
+ ) -> crate :: Result <MultiResults <' a, S >>
1606
1608
where
1607
- XS : ExactSizeIterator <Item = I >,
1609
+ XS : IntoIterator <Item = I >,
1608
1610
I : AsRef <[ IoSliceMut <' a>] >,
1609
1611
{
1610
- let count = std:: cmp:: min( slices. len( ) , data. items. len( ) ) ;
1611
-
1612
- for ( slice, mmsghdr) in slices. zip( data. items. iter_mut( ) ) {
1612
+ let mut count = 0 ;
1613
+ for ( i, ( slice, mmsghdr) ) in slices. into_iter( ) . zip( data. items. iter_mut( ) ) . enumerate( ) {
1613
1614
let mut p = & mut mmsghdr. msg_hdr;
1614
1615
p. msg_iov = slice. as_ref( ) . as_ptr( ) as * mut libc:: iovec;
1615
1616
p. msg_iovlen = slice. as_ref( ) . len( ) as _;
1617
+ count = i + 1 ;
1616
1618
}
1617
1619
1618
1620
let timeout_ptr = timeout
@@ -1629,7 +1631,7 @@ where
1629
1631
)
1630
1632
} ) ? as usize ;
1631
1633
1632
- Ok ( RecvMMsgItems {
1634
+ Ok ( MultiResults {
1633
1635
rmm: data,
1634
1636
current_index: 0 ,
1635
1637
received,
@@ -1643,9 +1645,12 @@ where
1643
1645
target_os = "netbsd" ,
1644
1646
) ) ]
1645
1647
#[ derive( Debug ) ]
1646
- pub struct RecvMMsgItems <' a, S > {
1648
+ /// Iterator over results of [`recvmmsg`]/[`sendmmsg`]
1649
+ ///
1650
+ ///
1651
+ pub struct MultiResults <' a, S > {
1647
1652
// preallocated structures
1648
- rmm: & ' a RecvMMsg <S >,
1653
+ rmm: & ' a MultHdrs <S >,
1649
1654
current_index: usize ,
1650
1655
received: usize ,
1651
1656
}
@@ -1656,11 +1661,11 @@ pub struct RecvMMsgItems<'a, S> {
1656
1661
target_os = "freebsd" ,
1657
1662
target_os = "netbsd" ,
1658
1663
) ) ]
1659
- impl <' a, S > Iterator for RecvMMsgItems <' a, S >
1664
+ impl <' a, S > Iterator for MultiResults <' a, S >
1660
1665
where
1661
1666
S : Copy + SockaddrLike ,
1662
1667
{
1663
- type Item = RecvMsg <' a, S >;
1668
+ type Item = RecvMsg <' a, ' a , S >;
1664
1669
1665
1670
fn next( & mut self ) -> Option <Self :: Item > {
1666
1671
if self . current_index >= self . received {
@@ -1684,13 +1689,17 @@ where
1684
1689
}
1685
1690
}
1686
1691
1687
- impl <' a, S > RecvMsg <' a, S > {
1692
+ impl <' a, S > RecvMsg <' _ , ' a, S > {
1688
1693
/// Iterate over the filled io slices pointed by this msghdr
1689
- pub fn iovs( & self ) -> IoSliceIterator {
1694
+ pub fn iovs( & self ) -> IoSliceIterator < ' a> {
1690
1695
IoSliceIterator {
1691
1696
index: 0 ,
1692
1697
remaining: self . bytes,
1693
1698
slices: unsafe {
1699
+ // safe for as long as mgdr is properly initialized and references are valid.
1700
+ // for multi messages API we initialize it with an empty
1701
+ // slice and replace with a concrete buffer
1702
+ // for single message API we hold a lifetime reference to ioslices
1694
1703
std:: slice:: from_raw_parts( self . mhdr. msg_iov as * const _, self . mhdr. msg_iovlen as _)
1695
1704
} ,
1696
1705
}
@@ -1782,7 +1791,7 @@ mod test {
1782
1791
let cmsg = cmsg_space!( crate :: sys:: socket:: Timestamps ) ;
1783
1792
sendmsg( ssock, & iov1, & [ ] , flags, Some ( & sock_addr) ) . unwrap( ) ;
1784
1793
1785
- let mut data = super :: RecvMMsg :: <( ) >:: preallocate( recv_iovs. len( ) , Some ( cmsg) ) ;
1794
+ let mut data = super :: MultHdrs :: <( ) >:: preallocate( recv_iovs. len( ) , Some ( cmsg) ) ;
1786
1795
1787
1796
let t = sys:: time:: TimeSpec :: from_duration( std:: time:: Duration :: from_secs( 10 ) ) ;
1788
1797
@@ -1817,12 +1826,12 @@ mod test {
1817
1826
Ok ( ( ) )
1818
1827
}
1819
1828
}
1820
- unsafe fn read_mhdr<' a, S >(
1829
+ unsafe fn read_mhdr<' a, ' i , S >(
1821
1830
mhdr: msghdr,
1822
1831
r: isize ,
1823
1832
msg_controllen: usize ,
1824
1833
address: S ,
1825
- ) -> RecvMsg <' a, S >
1834
+ ) -> RecvMsg <' a, ' i , S >
1826
1835
where S : SockaddrLike
1827
1836
{
1828
1837
let cmsghdr = {
@@ -1841,6 +1850,7 @@ unsafe fn read_mhdr<'a, S>(
1841
1850
address: Some ( address) ,
1842
1851
flags: MsgFlags :: from_bits_truncate( mhdr. msg_flags) ,
1843
1852
mhdr,
1853
+ iobufs: std:: marker:: PhantomData ,
1844
1854
}
1845
1855
}
1846
1856
@@ -1948,8 +1958,9 @@ fn pack_mhdr_to_send<'a, I, C, S>(
1948
1958
/// [recvmsg(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html)
1949
1959
pub fn recvmsg<' a, ' outer, ' inner, S >( fd: RawFd , iov: & ' outer mut [ IoSliceMut <' inner>] ,
1950
1960
mut cmsg_buffer: Option <& ' a mut Vec <u8 >>,
1951
- flags: MsgFlags ) -> Result <RecvMsg <' a, S >>
1952
- where S : SockaddrLike + ' a
1961
+ flags: MsgFlags ) -> Result <RecvMsg <' a, ' inner, S >>
1962
+ where S : SockaddrLike + ' a,
1963
+ ' inner: ' outer
1953
1964
{
1954
1965
let mut address = mem:: MaybeUninit :: uninit( ) ;
1955
1966
0 commit comments