@@ -17,7 +17,34 @@ use core::{ptr, slice};
17
17
18
18
use super :: { RecvFlags , SendFlags , SocketAddrAny , SocketAddrV4 , SocketAddrV6 } ;
19
19
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
+ /// ```
21
48
#[ macro_export]
22
49
macro_rules! cmsg_space {
23
50
// Base Rules
@@ -33,12 +60,41 @@ macro_rules! cmsg_space {
33
60
} ;
34
61
35
62
// 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) ) ;
37
67
$(
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
+ )
41
88
} ;
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
+ } } ;
42
98
}
43
99
44
100
#[ doc( hidden) ]
@@ -47,6 +103,11 @@ pub const fn __cmsg_space(len: usize) -> usize {
47
103
// `&[u8]` to the required alignment boundary.
48
104
let len = len + align_of :: < c:: cmsghdr > ( ) ;
49
105
106
+ __cmsg_aligned_space ( len)
107
+ }
108
+
109
+ #[ doc( hidden) ]
110
+ pub const fn __cmsg_aligned_space ( len : usize ) -> usize {
50
111
// Convert `len` to `u32` for `CMSG_SPACE`. This would be `try_into()` if
51
112
// we could call that in a `const fn`.
52
113
let converted_len = len as u32 ;
@@ -97,6 +158,10 @@ pub enum RecvAncillaryMessage<'a> {
97
158
98
159
/// Buffer for sending ancillary messages with [`sendmsg`], [`sendmsg_v4`],
99
160
/// [`sendmsg_v6`], [`sendmsg_unix`], and [`sendmsg_any`].
161
+ ///
162
+ /// Use the [`push`] function to add messages to send.
163
+ ///
164
+ /// [`push`]: SendAncillaryBuffer::push
100
165
pub struct SendAncillaryBuffer < ' buf , ' slice , ' fd > {
101
166
/// Raw byte buffer for messages.
102
167
buffer : & ' buf mut [ u8 ] ,
@@ -126,6 +191,44 @@ impl Default for SendAncillaryBuffer<'_, '_, '_> {
126
191
127
192
impl < ' buf , ' slice , ' fd > SendAncillaryBuffer < ' buf , ' slice , ' fd > {
128
193
/// 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
129
232
#[ inline]
130
233
pub fn new ( buffer : & ' buf mut [ u8 ] ) -> Self {
131
234
Self {
@@ -229,6 +332,10 @@ impl<'slice, 'fd> Extend<SendAncillaryMessage<'slice, 'fd>>
229
332
}
230
333
231
334
/// Buffer for receiving ancillary messages with [`recvmsg`].
335
+ ///
336
+ /// Use the [`drain`] function to iterate over the received messages.
337
+ ///
338
+ /// [`drain`]: RecvAncillaryBuffer::drain
232
339
#[ derive( Default ) ]
233
340
pub struct RecvAncillaryBuffer < ' buf > {
234
341
/// Raw byte buffer for messages.
@@ -249,6 +356,44 @@ impl<'buf> From<&'buf mut [u8]> for RecvAncillaryBuffer<'buf> {
249
356
250
357
impl < ' buf > RecvAncillaryBuffer < ' buf > {
251
358
/// 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
252
397
#[ inline]
253
398
pub fn new ( buffer : & ' buf mut [ u8 ] ) -> Self {
254
399
Self {
@@ -311,6 +456,12 @@ impl Drop for RecvAncillaryBuffer<'_> {
311
456
/// boundary.
312
457
#[ inline]
313
458
fn 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
+
314
465
let align = align_of :: < c:: cmsghdr > ( ) ;
315
466
let addr = buffer. as_ptr ( ) as usize ;
316
467
let adjusted = ( addr + ( align - 1 ) ) & align. wrapping_neg ( ) ;
0 commit comments