@@ -17,7 +17,34 @@ use core::{ptr, slice};
1717
1818use super :: { RecvFlags , SendFlags , SocketAddrAny , SocketAddrV4 , SocketAddrV6 } ;
1919
20- /// Macro for defining the amount of space used by CMSGs.
20+ /// Macro for defining the amount of space to allocate in a buffer for use with
21+ /// [`RecvAncillaryBuffer::new`] and [`SendAncillaryBuffer::new`].
22+ ///
23+ /// # Examples
24+ ///
25+ /// Allocate a buffer for a single file descriptor:
26+ /// ```
27+ /// # use rustix::cmsg_space;
28+ /// let mut space = [0; rustix::cmsg_space!(ScmRights(1))];
29+ /// ```
30+ ///
31+ /// Allocate a buffer for credentials:
32+ /// ```
33+ /// # #[cfg(linux_kernel)]
34+ /// # {
35+ /// # use rustix::cmsg_space;
36+ /// let mut space = [0; rustix::cmsg_space!(ScmCredentials(1))];
37+ /// # }
38+ /// ```
39+ ///
40+ /// Allocate a buffer for two file descriptors and credentials:
41+ /// ```
42+ /// # #[cfg(linux_kernel)]
43+ /// # {
44+ /// # use rustix::cmsg_space;
45+ /// let mut space = [0; rustix::cmsg_space!(ScmRights(2), ScmCredentials(1))];
46+ /// # }
47+ /// ```
2148#[ macro_export]
2249macro_rules! cmsg_space {
2350 // Base Rules
@@ -33,12 +60,41 @@ macro_rules! cmsg_space {
3360 } ;
3461
3562 // Combo Rules
36- ( ( $( $( $x: tt) * ) ,+) ) => {
63+ ( $firstid: ident( $firstex: expr) , $( $restid: ident( $restex: expr) ) ,* ) => { {
64+ // We only have to add `cmsghdr` alignment once; all other times we can
65+ // use `cmsg_aligned_space`.
66+ let sum = $crate:: cmsg_space!( $firstid( $firstex) ) ;
3767 $(
38- cmsg_space!( $( $x) * ) +
39- ) +
40- 0
68+ let sum = sum + $crate:: cmsg_aligned_space!( $restid( $restex) ) ;
69+ ) *
70+ sum
71+ } } ;
72+ }
73+
74+ /// Like `cmsg_space`, but doesn't add padding for `cmsghdr` alignment.
75+ #[ doc( hidden) ]
76+ #[ macro_export]
77+ macro_rules! cmsg_aligned_space {
78+ // Base Rules
79+ ( ScmRights ( $len: expr) ) => {
80+ $crate:: net:: __cmsg_aligned_space(
81+ $len * :: core:: mem:: size_of:: <$crate:: fd:: BorrowedFd <' static >>( ) ,
82+ )
83+ } ;
84+ ( ScmCredentials ( $len: expr) ) => {
85+ $crate:: net:: __cmsg_aligned_space(
86+ $len * :: core:: mem:: size_of:: <$crate:: net:: UCred >( ) ,
87+ )
4188 } ;
89+
90+ // Combo Rules
91+ ( $firstid: ident( $firstex: expr) , $( $restid: ident( $restex: expr) ) ,* ) => { {
92+ let sum = cmsg_aligned_space!( $firstid( $firstex) ) ;
93+ $(
94+ let sum = sum + cmsg_aligned_space!( $restid( $restex) ) ;
95+ ) *
96+ sum
97+ } } ;
4298}
4399
44100#[ doc( hidden) ]
@@ -47,6 +103,11 @@ pub const fn __cmsg_space(len: usize) -> usize {
47103 // `&[u8]` to the required alignment boundary.
48104 let len = len + align_of :: < c:: cmsghdr > ( ) ;
49105
106+ __cmsg_aligned_space ( len)
107+ }
108+
109+ #[ doc( hidden) ]
110+ pub const fn __cmsg_aligned_space ( len : usize ) -> usize {
50111 // Convert `len` to `u32` for `CMSG_SPACE`. This would be `try_into()` if
51112 // we could call that in a `const fn`.
52113 let converted_len = len as u32 ;
@@ -97,6 +158,10 @@ pub enum RecvAncillaryMessage<'a> {
97158
98159/// Buffer for sending ancillary messages with [`sendmsg`], [`sendmsg_v4`],
99160/// [`sendmsg_v6`], [`sendmsg_unix`], and [`sendmsg_any`].
161+ ///
162+ /// Use the [`push`] function to add messages to send.
163+ ///
164+ /// [`push`]: SendAncillaryBuffer::push
100165pub struct SendAncillaryBuffer < ' buf , ' slice , ' fd > {
101166 /// Raw byte buffer for messages.
102167 buffer : & ' buf mut [ u8 ] ,
@@ -126,6 +191,44 @@ impl Default for SendAncillaryBuffer<'_, '_, '_> {
126191
127192impl < ' buf , ' slice , ' fd > SendAncillaryBuffer < ' buf , ' slice , ' fd > {
128193 /// Create a new, empty `SendAncillaryBuffer` from a raw byte buffer.
194+ ///
195+ /// The buffer size may be computed with [`cmsg_space`], or it may be
196+ /// zero for an empty buffer, however in that case, consider `default()`
197+ /// instead, or even using [`send`] instead of `sendmsg`.
198+ ///
199+ /// # Examples
200+ ///
201+ /// Allocate a buffer for a single file descriptor:
202+ /// ```
203+ /// # use rustix::cmsg_space;
204+ /// # use rustix::net::SendAncillaryBuffer;
205+ /// let mut space = [0; rustix::cmsg_space!(ScmRights(1))];
206+ /// let mut cmsg_buffer = SendAncillaryBuffer::new(&mut space);
207+ /// ```
208+ ///
209+ /// Allocate a buffer for credentials:
210+ /// ```
211+ /// # #[cfg(linux_kernel)]
212+ /// # {
213+ /// # use rustix::cmsg_space;
214+ /// # use rustix::net::SendAncillaryBuffer;
215+ /// let mut space = [0; rustix::cmsg_space!(ScmCredentials(1))];
216+ /// let mut cmsg_buffer = SendAncillaryBuffer::new(&mut space);
217+ /// # }
218+ /// ```
219+ ///
220+ /// Allocate a buffer for two file descriptors and credentials:
221+ /// ```
222+ /// # #[cfg(linux_kernel)]
223+ /// # {
224+ /// # use rustix::cmsg_space;
225+ /// # use rustix::net::SendAncillaryBuffer;
226+ /// let mut space = [0; rustix::cmsg_space!(ScmRights(2), ScmCredentials(1))];
227+ /// let mut cmsg_buffer = SendAncillaryBuffer::new(&mut space);
228+ /// # }
229+ /// ```
230+ ///
231+ /// [`send`]: crate::net::send
129232 #[ inline]
130233 pub fn new ( buffer : & ' buf mut [ u8 ] ) -> Self {
131234 Self {
@@ -229,6 +332,10 @@ impl<'slice, 'fd> Extend<SendAncillaryMessage<'slice, 'fd>>
229332}
230333
231334/// Buffer for receiving ancillary messages with [`recvmsg`].
335+ ///
336+ /// Use the [`drain`] function to iterate over the received messages.
337+ ///
338+ /// [`drain`]: RecvAncillaryBuffer::drain
232339#[ derive( Default ) ]
233340pub struct RecvAncillaryBuffer < ' buf > {
234341 /// Raw byte buffer for messages.
@@ -249,6 +356,44 @@ impl<'buf> From<&'buf mut [u8]> for RecvAncillaryBuffer<'buf> {
249356
250357impl < ' buf > RecvAncillaryBuffer < ' buf > {
251358 /// Create a new, empty `RecvAncillaryBuffer` from a raw byte buffer.
359+ ///
360+ /// The buffer size may be computed with [`cmsg_space`], or it may be
361+ /// zero for an empty buffer, however in that case, consider `default()`
362+ /// instead, or even using [`recv`] instead of `recvmsg`.
363+ ///
364+ /// # Examples
365+ ///
366+ /// Allocate a buffer for a single file descriptor:
367+ /// ```
368+ /// # use rustix::cmsg_space;
369+ /// # use rustix::net::RecvAncillaryBuffer;
370+ /// let mut space = [0; rustix::cmsg_space!(ScmRights(1))];
371+ /// let mut cmsg_buffer = RecvAncillaryBuffer::new(&mut space);
372+ /// ```
373+ ///
374+ /// Allocate a buffer for credentials:
375+ /// ```
376+ /// # #[cfg(linux_kernel)]
377+ /// # {
378+ /// # use rustix::cmsg_space;
379+ /// # use rustix::net::RecvAncillaryBuffer;
380+ /// let mut space = [0; rustix::cmsg_space!(ScmCredentials(1))];
381+ /// let mut cmsg_buffer = RecvAncillaryBuffer::new(&mut space);
382+ /// # }
383+ /// ```
384+ ///
385+ /// Allocate a buffer for two file descriptors and credentials:
386+ /// ```
387+ /// # #[cfg(linux_kernel)]
388+ /// # {
389+ /// # use rustix::cmsg_space;
390+ /// # use rustix::net::RecvAncillaryBuffer;
391+ /// let mut space = [0; rustix::cmsg_space!(ScmRights(2), ScmCredentials(1))];
392+ /// let mut cmsg_buffer = RecvAncillaryBuffer::new(&mut space);
393+ /// # }
394+ /// ```
395+ ///
396+ /// [`recv`]: crate::net::recv
252397 #[ inline]
253398 pub fn new ( buffer : & ' buf mut [ u8 ] ) -> Self {
254399 Self {
@@ -311,6 +456,12 @@ impl Drop for RecvAncillaryBuffer<'_> {
311456/// boundary.
312457#[ inline]
313458fn align_for_cmsghdr ( buffer : & mut [ u8 ] ) -> & mut [ u8 ] {
459+ // If the buffer is empty, we won't be writing anything into it, so it
460+ // doesn't need to be aligned.
461+ if buffer. is_empty ( ) {
462+ return buffer;
463+ }
464+
314465 let align = align_of :: < c:: cmsghdr > ( ) ;
315466 let addr = buffer. as_ptr ( ) as usize ;
316467 let adjusted = ( addr + ( align - 1 ) ) & align. wrapping_neg ( ) ;
0 commit comments