rustix/net/send_recv/msg.rs
1//! [`recvmsg`], [`sendmsg`], and related functions.
2
3#![allow(unsafe_code)]
4
5#[cfg(target_os = "linux")]
6use crate::backend::net::msghdr::noaddr_msghdr;
7use crate::backend::{self, c};
8use crate::fd::{AsFd, BorrowedFd, OwnedFd};
9use crate::io::{self, IoSlice, IoSliceMut};
10use crate::net::addr::SocketAddrArg;
11#[cfg(linux_kernel)]
12use crate::net::UCred;
13use core::iter::FusedIterator;
14use core::marker::PhantomData;
15use core::mem::{align_of, size_of, size_of_val, take, MaybeUninit};
16#[cfg(linux_kernel)]
17use core::ptr::addr_of;
18use core::{ptr, slice};
19
20use super::{RecvFlags, ReturnFlags, SendFlags, SocketAddrAny};
21
22/// Macro for defining the amount of space to allocate in a buffer for use with
23/// [`RecvAncillaryBuffer::new`] and [`SendAncillaryBuffer::new`].
24///
25/// # Examples
26///
27/// Allocate a buffer for a single file descriptor:
28/// ```
29/// # use std::mem::MaybeUninit;
30/// # use rustix::cmsg_space;
31/// let mut space = [MaybeUninit::uninit(); rustix::cmsg_space!(ScmRights(1))];
32/// # let _: &[MaybeUninit<u8>] = space.as_slice();
33/// ```
34///
35/// Allocate a buffer for credentials:
36/// ```
37/// # #[cfg(linux_kernel)]
38/// # {
39/// # use std::mem::MaybeUninit;
40/// # use rustix::cmsg_space;
41/// let mut space = [MaybeUninit::uninit(); rustix::cmsg_space!(ScmCredentials(1))];
42/// # let _: &[MaybeUninit<u8>] = space.as_slice();
43/// # }
44/// ```
45///
46/// Allocate a buffer for two file descriptors and credentials:
47/// ```
48/// # #[cfg(linux_kernel)]
49/// # {
50/// # use std::mem::MaybeUninit;
51/// # use rustix::cmsg_space;
52/// let mut space = [MaybeUninit::uninit(); rustix::cmsg_space!(ScmRights(2), ScmCredentials(1))];
53/// # let _: &[MaybeUninit<u8>] = space.as_slice();
54/// # }
55/// ```
56#[macro_export]
57macro_rules! cmsg_space {
58 // Base Rules
59 (ScmRights($len:expr)) => {
60 $crate::net::__cmsg_space(
61 $len * ::core::mem::size_of::<$crate::fd::BorrowedFd<'static>>(),
62 )
63 };
64 (ScmCredentials($len:expr)) => {
65 $crate::net::__cmsg_space(
66 $len * ::core::mem::size_of::<$crate::net::UCred>(),
67 )
68 };
69 (TxTime($len:expr)) => {
70 $crate::net::__cmsg_space(
71 $len * ::core::mem::size_of::<::core::primitive::u64>(),
72 )
73 };
74
75 // Combo Rules
76 ($firstid:ident($firstex:expr), $($restid:ident($restex:expr)),*) => {{
77 // We only have to add `cmsghdr` alignment once; all other times we can
78 // use `cmsg_aligned_space`.
79 let sum = $crate::cmsg_space!($firstid($firstex));
80 $(
81 let sum = sum + $crate::cmsg_aligned_space!($restid($restex));
82 )*
83 sum
84 }};
85}
86
87/// Like `cmsg_space`, but doesn't add padding for `cmsghdr` alignment.
88#[doc(hidden)]
89#[macro_export]
90macro_rules! cmsg_aligned_space {
91 // Base Rules
92 (ScmRights($len:expr)) => {
93 $crate::net::__cmsg_aligned_space(
94 $len * ::core::mem::size_of::<$crate::fd::BorrowedFd<'static>>(),
95 )
96 };
97 (ScmCredentials($len:expr)) => {
98 $crate::net::__cmsg_aligned_space(
99 $len * ::core::mem::size_of::<$crate::net::UCred>(),
100 )
101 };
102 (TxTime($len:expr)) => {
103 $crate::net::__cmsg_aligned_space(
104 $len * ::core::mem::size_of::<::core::primitive::u64>(),
105 )
106 };
107
108 // Combo Rules
109 ($firstid:ident($firstex:expr), $($restid:ident($restex:expr)),*) => {{
110 let sum = $crate::cmsg_aligned_space!($firstid($firstex));
111 $(
112 let sum = sum + $crate::cmsg_aligned_space!($restid($restex));
113 )*
114 sum
115 }};
116}
117
118/// Helper function for [`cmsg_space`].
119#[doc(hidden)]
120pub const fn __cmsg_space(len: usize) -> usize {
121 // Add `align_of::<c::cmsghdr>()` so that we can align the user-provided
122 // `&[u8]` to the required alignment boundary.
123 let len = len + align_of::<c::cmsghdr>();
124
125 __cmsg_aligned_space(len)
126}
127
128/// Helper function for [`cmsg_aligned_space`].
129#[doc(hidden)]
130pub const fn __cmsg_aligned_space(len: usize) -> usize {
131 // Convert `len` to `u32` for `CMSG_SPACE`. This would be `try_into()` if
132 // we could call that in a `const fn`.
133 let converted_len = len as u32;
134 if converted_len as usize != len {
135 unreachable!(); // `CMSG_SPACE` size overflow
136 }
137
138 unsafe { c::CMSG_SPACE(converted_len) as usize }
139}
140
141/// Ancillary message for [`sendmsg`] and [`sendmsg_addr`].
142#[non_exhaustive]
143pub enum SendAncillaryMessage<'slice, 'fd> {
144 /// Send file descriptors.
145 #[doc(alias = "SCM_RIGHTS")]
146 ScmRights(&'slice [BorrowedFd<'fd>]),
147 /// Send process credentials.
148 #[cfg(linux_kernel)]
149 #[doc(alias = "SCM_CREDENTIAL")]
150 ScmCredentials(UCred),
151 /// Transmission time, in nanoseconds. The value will be interpreted by
152 /// whichever clock was configured on the socket with [`set_txtime`].
153 ///
154 /// [`set_txtime`]: crate::net::sockopt::set_txtime
155 #[cfg(target_os = "linux")]
156 #[doc(alias = "SCM_TXTIME")]
157 TxTime(u64),
158}
159
160impl SendAncillaryMessage<'_, '_> {
161 /// Get the maximum size of an ancillary message.
162 ///
163 /// This can be used to determine the size of the buffer to allocate for a
164 /// [`SendAncillaryBuffer::new`] with one message.
165 pub const fn size(&self) -> usize {
166 match self {
167 Self::ScmRights(slice) => cmsg_space!(ScmRights(slice.len())),
168 #[cfg(linux_kernel)]
169 Self::ScmCredentials(_) => cmsg_space!(ScmCredentials(1)),
170 #[cfg(target_os = "linux")]
171 Self::TxTime(_) => cmsg_space!(TxTime(1)),
172 }
173 }
174}
175
176/// Ancillary message for [`recvmsg`].
177#[non_exhaustive]
178pub enum RecvAncillaryMessage<'a> {
179 /// Received file descriptors.
180 #[doc(alias = "SCM_RIGHTS")]
181 ScmRights(AncillaryIter<'a, OwnedFd>),
182 /// Received process credentials.
183 #[cfg(linux_kernel)]
184 #[doc(alias = "SCM_CREDENTIALS")]
185 ScmCredentials(UCred),
186}
187
188/// Buffer for sending ancillary messages with [`sendmsg`] and
189/// [`sendmsg_addr`].
190///
191/// Use the [`push`] function to add messages to send.
192///
193/// [`push`]: SendAncillaryBuffer::push
194pub struct SendAncillaryBuffer<'buf, 'slice, 'fd> {
195 /// Raw byte buffer for messages.
196 buffer: &'buf mut [MaybeUninit<u8>],
197
198 /// The amount of the buffer that is used.
199 length: usize,
200
201 /// Phantom data for lifetime of `&'slice [BorrowedFd<'fd>]`.
202 _phantom: PhantomData<&'slice [BorrowedFd<'fd>]>,
203}
204
205impl<'buf> From<&'buf mut [MaybeUninit<u8>]> for SendAncillaryBuffer<'buf, '_, '_> {
206 fn from(buffer: &'buf mut [MaybeUninit<u8>]) -> Self {
207 Self::new(buffer)
208 }
209}
210
211impl Default for SendAncillaryBuffer<'_, '_, '_> {
212 fn default() -> Self {
213 Self {
214 buffer: &mut [],
215 length: 0,
216 _phantom: PhantomData,
217 }
218 }
219}
220
221impl<'buf, 'slice, 'fd> SendAncillaryBuffer<'buf, 'slice, 'fd> {
222 /// Create a new, empty `SendAncillaryBuffer` from a raw byte buffer.
223 ///
224 /// The buffer size may be computed with [`cmsg_space`], or it may be
225 /// zero for an empty buffer, however in that case, consider `default()`
226 /// instead, or even using [`send`] instead of `sendmsg`.
227 ///
228 /// # Examples
229 ///
230 /// Allocate a buffer for a single file descriptor:
231 /// ```
232 /// # use std::mem::MaybeUninit;
233 /// # use rustix::cmsg_space;
234 /// # use rustix::net::SendAncillaryBuffer;
235 /// let mut space = [MaybeUninit::uninit(); rustix::cmsg_space!(ScmRights(1))];
236 /// let mut cmsg_buffer = SendAncillaryBuffer::new(&mut space);
237 /// ```
238 ///
239 /// Allocate a buffer for credentials:
240 /// ```
241 /// # #[cfg(linux_kernel)]
242 /// # {
243 /// # use std::mem::MaybeUninit;
244 /// # use rustix::cmsg_space;
245 /// # use rustix::net::SendAncillaryBuffer;
246 /// let mut space = [MaybeUninit::uninit(); rustix::cmsg_space!(ScmCredentials(1))];
247 /// let mut cmsg_buffer = SendAncillaryBuffer::new(&mut space);
248 /// # }
249 /// ```
250 ///
251 /// Allocate a buffer for two file descriptors and credentials:
252 /// ```
253 /// # #[cfg(linux_kernel)]
254 /// # {
255 /// # use std::mem::MaybeUninit;
256 /// # use rustix::cmsg_space;
257 /// # use rustix::net::SendAncillaryBuffer;
258 /// let mut space = [MaybeUninit::uninit(); rustix::cmsg_space!(ScmRights(2), ScmCredentials(1))];
259 /// let mut cmsg_buffer = SendAncillaryBuffer::new(&mut space);
260 /// # }
261 /// ```
262 ///
263 /// [`send`]: crate::net::send
264 #[inline]
265 pub fn new(buffer: &'buf mut [MaybeUninit<u8>]) -> Self {
266 Self {
267 buffer: align_for_cmsghdr(buffer),
268 length: 0,
269 _phantom: PhantomData,
270 }
271 }
272
273 /// Returns a pointer to the message data.
274 pub(crate) fn as_control_ptr(&mut self) -> *mut u8 {
275 // When the length is zero, we may be using a `&[]` address, which may
276 // be an invalid but non-null pointer, and on some platforms, that
277 // causes `sendmsg` to fail with `EFAULT` or `EINVAL`
278 #[cfg(not(linux_kernel))]
279 if self.length == 0 {
280 return core::ptr::null_mut();
281 }
282
283 self.buffer.as_mut_ptr().cast()
284 }
285
286 /// Returns the length of the message data.
287 pub(crate) fn control_len(&self) -> usize {
288 self.length
289 }
290
291 /// Delete all messages from the buffer.
292 pub fn clear(&mut self) {
293 self.length = 0;
294 }
295
296 /// Add an ancillary message to the buffer.
297 ///
298 /// Returns `true` if the message was added successfully.
299 pub fn push(&mut self, msg: SendAncillaryMessage<'slice, 'fd>) -> bool {
300 match msg {
301 SendAncillaryMessage::ScmRights(fds) => {
302 let fds_bytes =
303 unsafe { slice::from_raw_parts(fds.as_ptr().cast::<u8>(), size_of_val(fds)) };
304 self.push_ancillary(fds_bytes, c::SOL_SOCKET as _, c::SCM_RIGHTS as _)
305 }
306 #[cfg(linux_kernel)]
307 SendAncillaryMessage::ScmCredentials(ucred) => {
308 let ucred_bytes = unsafe {
309 slice::from_raw_parts(addr_of!(ucred).cast::<u8>(), size_of_val(&ucred))
310 };
311 self.push_ancillary(ucred_bytes, c::SOL_SOCKET as _, c::SCM_CREDENTIALS as _)
312 }
313 #[cfg(target_os = "linux")]
314 SendAncillaryMessage::TxTime(tx_time) => {
315 let tx_time_bytes = unsafe {
316 slice::from_raw_parts(addr_of!(tx_time).cast::<u8>(), size_of_val(&tx_time))
317 };
318 self.push_ancillary(tx_time_bytes, c::SOL_SOCKET as _, c::SO_TXTIME as _)
319 }
320 }
321 }
322
323 /// Pushes an ancillary message to the buffer.
324 fn push_ancillary(&mut self, source: &[u8], cmsg_level: c::c_int, cmsg_type: c::c_int) -> bool {
325 macro_rules! leap {
326 ($e:expr) => {{
327 match ($e) {
328 Some(x) => x,
329 None => return false,
330 }
331 }};
332 }
333
334 // Calculate the length of the message.
335 let source_len = leap!(u32::try_from(source.len()).ok());
336
337 // Calculate the new length of the buffer.
338 let additional_space = unsafe { c::CMSG_SPACE(source_len) };
339 let new_length = leap!(self.length.checked_add(additional_space as usize));
340 let buffer = leap!(self.buffer.get_mut(..new_length));
341
342 // Fill the new part of the buffer with zeroes.
343 buffer[self.length..new_length].fill(MaybeUninit::new(0));
344 self.length = new_length;
345
346 // Get the last header in the buffer.
347 let (last_header, _) = leap!(messages::Messages::new(buffer).last());
348
349 // Set the header fields.
350 last_header.cmsg_len = unsafe { c::CMSG_LEN(source_len) } as _;
351 last_header.cmsg_level = cmsg_level;
352 last_header.cmsg_type = cmsg_type;
353
354 // Get the pointer to the payload and copy the data.
355 unsafe {
356 let payload = c::CMSG_DATA(last_header);
357 ptr::copy_nonoverlapping(source.as_ptr(), payload, source_len as usize);
358 }
359
360 true
361 }
362}
363
364impl<'slice, 'fd> Extend<SendAncillaryMessage<'slice, 'fd>>
365 for SendAncillaryBuffer<'_, 'slice, 'fd>
366{
367 fn extend<T: IntoIterator<Item = SendAncillaryMessage<'slice, 'fd>>>(&mut self, iter: T) {
368 // TODO: This could be optimized to add every message in one go.
369 iter.into_iter().all(|msg| self.push(msg));
370 }
371}
372
373/// Buffer for receiving ancillary messages with [`recvmsg`].
374///
375/// Use the [`drain`] function to iterate over the received messages.
376///
377/// [`drain`]: RecvAncillaryBuffer::drain
378#[derive(Default)]
379pub struct RecvAncillaryBuffer<'buf> {
380 /// Raw byte buffer for messages.
381 buffer: &'buf mut [MaybeUninit<u8>],
382
383 /// The portion of the buffer we've read from already.
384 read: usize,
385
386 /// The amount of the buffer that is used.
387 length: usize,
388}
389
390impl<'buf> From<&'buf mut [MaybeUninit<u8>]> for RecvAncillaryBuffer<'buf> {
391 fn from(buffer: &'buf mut [MaybeUninit<u8>]) -> Self {
392 Self::new(buffer)
393 }
394}
395
396impl<'buf> RecvAncillaryBuffer<'buf> {
397 /// Create a new, empty `RecvAncillaryBuffer` from a raw byte buffer.
398 ///
399 /// The buffer size may be computed with [`cmsg_space`], or it may be
400 /// zero for an empty buffer, however in that case, consider `default()`
401 /// instead, or even using [`recv`] instead of `recvmsg`.
402 ///
403 /// # Examples
404 ///
405 /// Allocate a buffer for a single file descriptor:
406 /// ```
407 /// # use std::mem::MaybeUninit;
408 /// # use rustix::cmsg_space;
409 /// # use rustix::net::RecvAncillaryBuffer;
410 /// let mut space = [MaybeUninit::uninit(); rustix::cmsg_space!(ScmRights(1))];
411 /// let mut cmsg_buffer = RecvAncillaryBuffer::new(&mut space);
412 /// ```
413 ///
414 /// Allocate a buffer for credentials:
415 /// ```
416 /// # #[cfg(linux_kernel)]
417 /// # {
418 /// # use std::mem::MaybeUninit;
419 /// # use rustix::cmsg_space;
420 /// # use rustix::net::RecvAncillaryBuffer;
421 /// let mut space = [MaybeUninit::uninit(); rustix::cmsg_space!(ScmCredentials(1))];
422 /// let mut cmsg_buffer = RecvAncillaryBuffer::new(&mut space);
423 /// # }
424 /// ```
425 ///
426 /// Allocate a buffer for two file descriptors and credentials:
427 /// ```
428 /// # #[cfg(linux_kernel)]
429 /// # {
430 /// # use std::mem::MaybeUninit;
431 /// # use rustix::cmsg_space;
432 /// # use rustix::net::RecvAncillaryBuffer;
433 /// let mut space = [MaybeUninit::uninit(); rustix::cmsg_space!(ScmRights(2), ScmCredentials(1))];
434 /// let mut cmsg_buffer = RecvAncillaryBuffer::new(&mut space);
435 /// # }
436 /// ```
437 ///
438 /// [`recv`]: crate::net::recv
439 #[inline]
440 pub fn new(buffer: &'buf mut [MaybeUninit<u8>]) -> Self {
441 Self {
442 buffer: align_for_cmsghdr(buffer),
443 read: 0,
444 length: 0,
445 }
446 }
447
448 /// Returns a pointer to the message data.
449 pub(crate) fn as_control_ptr(&mut self) -> *mut u8 {
450 // When the length is zero, we may be using a `&[]` address, which may
451 // be an invalid but non-null pointer, and on some platforms, that
452 // causes `sendmsg` to fail with `EFAULT` or `EINVAL`
453 #[cfg(not(linux_kernel))]
454 if self.buffer.is_empty() {
455 return core::ptr::null_mut();
456 }
457
458 self.buffer.as_mut_ptr().cast()
459 }
460
461 /// Returns the length of the message data.
462 pub(crate) fn control_len(&self) -> usize {
463 self.buffer.len()
464 }
465
466 /// Set the length of the message data.
467 ///
468 /// # Safety
469 ///
470 /// The buffer must be filled with valid message data.
471 pub(crate) unsafe fn set_control_len(&mut self, len: usize) {
472 self.length = len;
473 self.read = 0;
474 }
475
476 /// Delete all messages from the buffer.
477 pub(crate) fn clear(&mut self) {
478 self.drain().for_each(drop);
479 }
480
481 /// Drain all messages from the buffer.
482 pub fn drain(&mut self) -> AncillaryDrain<'_> {
483 AncillaryDrain {
484 messages: messages::Messages::new(&mut self.buffer[self.read..][..self.length]),
485 read_and_length: Some((&mut self.read, &mut self.length)),
486 }
487 }
488}
489
490impl Drop for RecvAncillaryBuffer<'_> {
491 fn drop(&mut self) {
492 self.clear();
493 }
494}
495
496/// Return a slice of `buffer` starting at the first `cmsghdr` alignment
497/// boundary.
498#[inline]
499fn align_for_cmsghdr(buffer: &mut [MaybeUninit<u8>]) -> &mut [MaybeUninit<u8>] {
500 // If the buffer is empty, we won't be writing anything into it, so it
501 // doesn't need to be aligned.
502 if buffer.is_empty() {
503 return buffer;
504 }
505
506 let align = align_of::<c::cmsghdr>();
507 let addr = buffer.as_ptr() as usize;
508 let adjusted = (addr + (align - 1)) & align.wrapping_neg();
509 &mut buffer[adjusted - addr..]
510}
511
512/// An iterator that drains messages from a [`RecvAncillaryBuffer`].
513pub struct AncillaryDrain<'buf> {
514 /// Inner iterator over messages.
515 messages: messages::Messages<'buf>,
516
517 /// Increment the number of messages we've read.
518 /// Decrement the total length.
519 read_and_length: Option<(&'buf mut usize, &'buf mut usize)>,
520}
521
522impl<'buf> AncillaryDrain<'buf> {
523 /// Create an iterator for control messages that were received without
524 /// [`RecvAncillaryBuffer`].
525 ///
526 /// # Safety
527 ///
528 /// The buffer must contain valid message data (or be empty).
529 pub unsafe fn parse(buffer: &'buf mut [u8]) -> Self {
530 Self {
531 messages: messages::Messages::new(buffer),
532 read_and_length: None,
533 }
534 }
535
536 /// `space` is the number of bytes of buffer space at and after `msg`.
537 fn advance(
538 read_and_length: &mut Option<(&'buf mut usize, &'buf mut usize)>,
539 msg: &c::cmsghdr,
540 space: usize,
541 ) -> Option<RecvAncillaryMessage<'buf>> {
542 // Clamp the message length to the buffer. When `recvmsg` truncates
543 // control data to fit, Linux reduces `cmsg_len` to match what it
544 // wrote, but macOS leaves `cmsg_len` holding the untruncated length,
545 // so it can run past the end of the buffer.
546 let msg_len = (msg.cmsg_len as usize).min(space);
547
548 // Advance the `read` pointer.
549 if let Some((read, length)) = read_and_length {
550 **read += msg_len;
551 **length -= msg_len;
552 }
553
554 Self::cvt_msg(msg, msg_len)
555 }
556
557 /// A closure that converts a message into a [`RecvAncillaryMessage`].
558 fn cvt_msg(msg: &c::cmsghdr, msg_len: usize) -> Option<RecvAncillaryMessage<'buf>> {
559 unsafe {
560 // Get a pointer to the payload. Use `msg_len` rather than
561 // `msg.cmsg_len`, as the message may have been truncated to fit
562 // in the buffer. If there isn't even a whole header, there's no
563 // message to report.
564 let payload = c::CMSG_DATA(msg);
565 let payload_len = msg_len.checked_sub(c::CMSG_LEN(0) as usize)?;
566
567 // Determine what type it is.
568 let (level, msg_type) = (msg.cmsg_level, msg.cmsg_type);
569 match (level as _, msg_type as _) {
570 (c::SOL_SOCKET, c::SCM_RIGHTS) => {
571 // Truncation can leave a partial file descriptor at the
572 // end of the payload; round down to whole descriptors.
573 let payload_len = payload_len - payload_len % size_of::<OwnedFd>();
574
575 // Get a mutable slice of the payload.
576 let payload: &'buf mut [u8] = slice::from_raw_parts_mut(payload, payload_len);
577
578 // Create an iterator that reads out the file descriptors.
579 let fds = AncillaryIter::new(payload);
580
581 Some(RecvAncillaryMessage::ScmRights(fds))
582 }
583 #[cfg(linux_kernel)]
584 (c::SOL_SOCKET, c::SCM_CREDENTIALS) => {
585 if payload_len >= size_of::<UCred>() {
586 let ucred = payload.cast::<UCred>().read_unaligned();
587 Some(RecvAncillaryMessage::ScmCredentials(ucred))
588 } else {
589 None
590 }
591 }
592 _ => None,
593 }
594 }
595 }
596}
597
598impl<'buf> Iterator for AncillaryDrain<'buf> {
599 type Item = RecvAncillaryMessage<'buf>;
600
601 fn next(&mut self) -> Option<Self::Item> {
602 self.messages
603 .find_map(|(msg, space)| Self::advance(&mut self.read_and_length, msg, space))
604 }
605
606 fn size_hint(&self) -> (usize, Option<usize>) {
607 let (_, max) = self.messages.size_hint();
608 (0, max)
609 }
610
611 fn fold<B, F>(mut self, init: B, f: F) -> B
612 where
613 Self: Sized,
614 F: FnMut(B, Self::Item) -> B,
615 {
616 self.messages
617 .filter_map(|(msg, space)| Self::advance(&mut self.read_and_length, msg, space))
618 .fold(init, f)
619 }
620
621 fn count(mut self) -> usize {
622 self.messages
623 .filter_map(|(msg, space)| Self::advance(&mut self.read_and_length, msg, space))
624 .count()
625 }
626
627 fn last(mut self) -> Option<Self::Item>
628 where
629 Self: Sized,
630 {
631 self.messages
632 .filter_map(|(msg, space)| Self::advance(&mut self.read_and_length, msg, space))
633 .last()
634 }
635
636 fn collect<B: FromIterator<Self::Item>>(mut self) -> B
637 where
638 Self: Sized,
639 {
640 self.messages
641 .filter_map(|(msg, space)| Self::advance(&mut self.read_and_length, msg, space))
642 .collect()
643 }
644}
645
646impl FusedIterator for AncillaryDrain<'_> {}
647
648/// An ABI-compatible wrapper for `mmsghdr`, for sending multiple messages with
649/// [sendmmsg].
650#[cfg(target_os = "linux")]
651#[repr(transparent)]
652pub struct MMsgHdr<'a> {
653 raw: c::mmsghdr,
654 _phantom: PhantomData<&'a mut ()>,
655}
656
657#[cfg(target_os = "linux")]
658impl<'a> MMsgHdr<'a> {
659 /// Constructs a new message with no destination address.
660 pub fn new(iov: &'a [IoSlice<'_>], control: &'a mut SendAncillaryBuffer<'_, '_, '_>) -> Self {
661 Self::wrap(noaddr_msghdr(iov, control))
662 }
663
664 /// Constructs a new message to a specific address.
665 ///
666 /// This requires a `SocketAddrAny` instead of using `impl SocketAddrArg`;
667 /// to obtain a `SocketAddrAny`, use [`SocketAddrArg::as_any`].
668 pub fn new_with_addr(
669 addr: &'a SocketAddrAny,
670 iov: &'a [IoSlice<'_>],
671 control: &'a mut SendAncillaryBuffer<'_, '_, '_>,
672 ) -> Self {
673 // The reason we use `SocketAddrAny` instead of `SocketAddrArg` here,
674 // and avoid `use_msghdr`, is that we need a pointer that will remain
675 // valid for the duration of the `'a` lifetime. `SocketAddrAny` can
676 // give us a pointer directly, so we use that.
677 let mut msghdr = noaddr_msghdr(iov, control);
678 msghdr.msg_name = addr.as_ptr() as _;
679 msghdr.msg_namelen = bitcast!(addr.addr_len());
680
681 Self::wrap(msghdr)
682 }
683
684 fn wrap(msg_hdr: c::msghdr) -> Self {
685 Self {
686 raw: c::mmsghdr {
687 msg_hdr,
688 msg_len: 0,
689 },
690 _phantom: PhantomData,
691 }
692 }
693
694 /// Returns the number of bytes sent. This will return 0 until after a
695 /// successful call to [sendmmsg].
696 pub fn bytes_sent(&self) -> usize {
697 self.raw.msg_len as usize
698 }
699}
700
701/// `sendmsg(msghdr)`—Sends a message on a socket.
702///
703/// This function is for use on connected sockets, as it doesn't have a way to
704/// specify an address. See [`sendmsg_addr`] to send messages on unconnected
705/// sockets.
706///
707/// # References
708/// - [POSIX]
709/// - [Linux]
710/// - [Apple]
711/// - [FreeBSD]
712/// - [NetBSD]
713/// - [OpenBSD]
714/// - [DragonFly BSD]
715/// - [illumos]
716///
717/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/sendmsg.html
718/// [Linux]: https://man7.org/linux/man-pages/man2/sendmsg.2.html
719/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendmsg.2.html
720/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendmsg&sektion=2
721/// [NetBSD]: https://man.netbsd.org/sendmsg.2
722/// [OpenBSD]: https://man.openbsd.org/sendmsg.2
723/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendmsg§ion=2
724/// [illumos]: https://illumos.org/man/3SOCKET/sendmsg
725#[inline]
726pub fn sendmsg<Fd: AsFd>(
727 socket: Fd,
728 iov: &[IoSlice<'_>],
729 control: &mut SendAncillaryBuffer<'_, '_, '_>,
730 flags: SendFlags,
731) -> io::Result<usize> {
732 backend::net::syscalls::sendmsg(socket.as_fd(), iov, control, flags)
733}
734
735/// `sendmsg(msghdr)`—Sends a message on a socket to a specific address.
736///
737/// # References
738/// - [POSIX]
739/// - [Linux]
740/// - [Apple]
741/// - [FreeBSD]
742/// - [NetBSD]
743/// - [OpenBSD]
744/// - [DragonFly BSD]
745/// - [illumos]
746///
747/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/sendmsg.html
748/// [Linux]: https://man7.org/linux/man-pages/man2/sendmsg.2.html
749/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendmsg.2.html
750/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendmsg&sektion=2
751/// [NetBSD]: https://man.netbsd.org/sendmsg.2
752/// [OpenBSD]: https://man.openbsd.org/sendmsg.2
753/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendmsg§ion=2
754/// [illumos]: https://illumos.org/man/3SOCKET/sendmsg
755#[inline]
756pub fn sendmsg_addr<Fd: AsFd>(
757 socket: Fd,
758 addr: &impl SocketAddrArg,
759 iov: &[IoSlice<'_>],
760 control: &mut SendAncillaryBuffer<'_, '_, '_>,
761 flags: SendFlags,
762) -> io::Result<usize> {
763 backend::net::syscalls::sendmsg_addr(socket.as_fd(), addr, iov, control, flags)
764}
765
766/// `sendmmsg(msghdr)`—Sends multiple messages on a socket.
767///
768/// # References
769/// - [Linux]
770///
771/// [Linux]: https://man7.org/linux/man-pages/man2/sendmmsg.2.html
772#[inline]
773#[cfg(target_os = "linux")]
774pub fn sendmmsg<Fd: AsFd>(
775 socket: Fd,
776 msgs: &mut [MMsgHdr<'_>],
777 flags: SendFlags,
778) -> io::Result<usize> {
779 backend::net::syscalls::sendmmsg(socket.as_fd(), msgs, flags)
780}
781
782/// `recvmsg(msghdr)`—Receives a message from a socket.
783///
784/// # References
785/// - [POSIX]
786/// - [Linux]
787/// - [Apple]
788/// - [FreeBSD]
789/// - [NetBSD]
790/// - [OpenBSD]
791/// - [DragonFly BSD]
792/// - [illumos]
793///
794/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/recvmsg.html
795/// [Linux]: https://man7.org/linux/man-pages/man2/recvmsg.2.html
796/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/recvmsg.2.html
797/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=recvmsg&sektion=2
798/// [NetBSD]: https://man.netbsd.org/recvmsg.2
799/// [OpenBSD]: https://man.openbsd.org/recvmsg.2
800/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=recvmsg§ion=2
801/// [illumos]: https://illumos.org/man/3SOCKET/recvmsg
802#[inline]
803pub fn recvmsg<Fd: AsFd>(
804 socket: Fd,
805 iov: &mut [IoSliceMut<'_>],
806 control: &mut RecvAncillaryBuffer<'_>,
807 flags: RecvFlags,
808) -> io::Result<RecvMsg> {
809 backend::net::syscalls::recvmsg(socket.as_fd(), iov, control, flags)
810}
811
812/// The result of a successful [`recvmsg`] call.
813#[derive(Debug, Clone)]
814pub struct RecvMsg {
815 /// The number of bytes received.
816 ///
817 /// When `RecvFlags::TRUNC` is in use, this may be greater than the length
818 /// of the buffer, as it reflects the number of bytes received before
819 /// truncation into the buffer.
820 pub bytes: usize,
821
822 /// The flags received.
823 pub flags: ReturnFlags,
824
825 /// The address of the socket we received from, if any.
826 pub address: Option<SocketAddrAny>,
827}
828
829/// An iterator over data in an ancillary buffer.
830pub struct AncillaryIter<'data, T> {
831 /// The data we're iterating over.
832 data: &'data mut [u8],
833
834 /// The raw data we're removing.
835 _marker: PhantomData<T>,
836}
837
838impl<'data, T> AncillaryIter<'data, T> {
839 /// Create a new iterator over data in an ancillary buffer.
840 ///
841 /// # Safety
842 ///
843 /// The buffer must contain valid ancillary data.
844 unsafe fn new(data: &'data mut [u8]) -> Self {
845 assert_eq!(data.len() % size_of::<T>(), 0);
846
847 Self {
848 data,
849 _marker: PhantomData,
850 }
851 }
852}
853
854impl<'data, T> Drop for AncillaryIter<'data, T> {
855 fn drop(&mut self) {
856 self.for_each(drop);
857 }
858}
859
860impl<T> Iterator for AncillaryIter<'_, T> {
861 type Item = T;
862
863 fn next(&mut self) -> Option<Self::Item> {
864 // See if there is a next item.
865 if self.data.len() < size_of::<T>() {
866 return None;
867 }
868
869 // Get the next item.
870 let item = unsafe { self.data.as_ptr().cast::<T>().read_unaligned() };
871
872 // Move forward.
873 let data = take(&mut self.data);
874 self.data = &mut data[size_of::<T>()..];
875
876 Some(item)
877 }
878
879 fn size_hint(&self) -> (usize, Option<usize>) {
880 let len = self.len();
881 (len, Some(len))
882 }
883
884 fn count(self) -> usize {
885 self.len()
886 }
887
888 fn last(mut self) -> Option<Self::Item> {
889 self.next_back()
890 }
891}
892
893impl<T> FusedIterator for AncillaryIter<'_, T> {}
894
895impl<T> ExactSizeIterator for AncillaryIter<'_, T> {
896 fn len(&self) -> usize {
897 self.data.len() / size_of::<T>()
898 }
899}
900
901impl<T> DoubleEndedIterator for AncillaryIter<'_, T> {
902 fn next_back(&mut self) -> Option<Self::Item> {
903 // See if there is a next item.
904 if self.data.len() < size_of::<T>() {
905 return None;
906 }
907
908 // Get the next item.
909 let item = unsafe {
910 let ptr = self.data.as_ptr().add(self.data.len() - size_of::<T>());
911 ptr.cast::<T>().read_unaligned()
912 };
913
914 // Move forward.
915 let len = self.data.len();
916 let data = take(&mut self.data);
917 self.data = &mut data[..len - size_of::<T>()];
918
919 Some(item)
920 }
921}
922
923mod messages {
924 use crate::backend::c;
925 use crate::backend::net::msghdr;
926 use core::iter::FusedIterator;
927 use core::marker::PhantomData;
928 use core::mem::MaybeUninit;
929 use core::ptr::NonNull;
930
931 /// An iterator over the messages in an ancillary buffer.
932 pub(super) struct Messages<'buf> {
933 /// The message header we're using to iterate over the messages.
934 msghdr: c::msghdr,
935
936 /// The current pointer to the next message header to return.
937 ///
938 /// This has a lifetime of `'buf`.
939 header: Option<NonNull<c::cmsghdr>>,
940
941 /// Capture the original lifetime of the buffer.
942 _buffer: PhantomData<&'buf mut [MaybeUninit<u8>]>,
943 }
944
945 pub(super) trait AllowedMsgBufType {}
946 impl AllowedMsgBufType for u8 {}
947 impl AllowedMsgBufType for MaybeUninit<u8> {}
948
949 impl<'buf> Messages<'buf> {
950 /// Create a new iterator over messages from a byte buffer.
951 pub(super) fn new(buf: &'buf mut [impl AllowedMsgBufType]) -> Self {
952 let mut msghdr = msghdr::zero_msghdr();
953 msghdr.msg_control = buf.as_mut_ptr().cast();
954 msghdr.msg_controllen = buf.len().try_into().expect("buffer too large for msghdr");
955
956 // Get the first header.
957 let header = NonNull::new(unsafe { c::CMSG_FIRSTHDR(&msghdr) });
958
959 Self {
960 msghdr,
961 header,
962 _buffer: PhantomData,
963 }
964 }
965 }
966
967 impl<'a> Iterator for Messages<'a> {
968 /// A message header, along with the number of bytes of buffer space
969 /// at and after it, which is an upper bound on the size of the
970 /// message.
971 type Item = (&'a mut c::cmsghdr, usize);
972
973 #[inline]
974 fn next(&mut self) -> Option<Self::Item> {
975 // Get the current header.
976 let header = self.header?;
977
978 // Compute the number of bytes of buffer space at and after this
979 // header.
980 let end = (self.msghdr.msg_control as usize) + (self.msghdr.msg_controllen as usize);
981 let space = end.saturating_sub(header.as_ptr() as usize);
982
983 // Get the next header.
984 self.header = NonNull::new(unsafe { c::CMSG_NXTHDR(&self.msghdr, header.as_ptr()) });
985
986 // If the headers are equal, we're done.
987 if Some(header) == self.header {
988 self.header = None;
989 }
990
991 // SAFETY: The lifetime of `header` is tied to this.
992 Some((unsafe { &mut *header.as_ptr() }, space))
993 }
994
995 fn size_hint(&self) -> (usize, Option<usize>) {
996 if self.header.is_some() {
997 // The remaining buffer *could* be filled with zero-length
998 // messages.
999 let max_size = unsafe { c::CMSG_LEN(0) } as usize;
1000 let remaining_count = self.msghdr.msg_controllen as usize / max_size;
1001 (1, Some(remaining_count))
1002 } else {
1003 (0, Some(0))
1004 }
1005 }
1006 }
1007
1008 impl FusedIterator for Messages<'_> {}
1009}
1010
1011#[cfg(test)]
1012mod tests {
1013 #[no_implicit_prelude]
1014 mod hygiene {
1015 #[allow(unused_macros)]
1016 #[test]
1017 fn macro_hygiene() {
1018 // This `u64` is `!Sized`, so `cmsg_space!` will fail if it tries to get its size with
1019 // `size_of()`.
1020 #[allow(dead_code, non_camel_case_types)]
1021 struct u64([u8]);
1022
1023 // Ensure that when `cmsg*_space!` calls itself recursively, it really calls itself and
1024 // not these macros.
1025 macro_rules! cmsg_space {
1026 ($($tt:tt)*) => {{
1027 let v: usize = ::core::panic!("Wrong cmsg_space! macro called");
1028 v
1029 }};
1030 }
1031 macro_rules! cmsg_aligned_space {
1032 ($($tt:tt)*) => {{
1033 let v: usize = ::core::panic!("Wrong cmsg_aligned_space! macro called");
1034 v
1035 }};
1036 }
1037
1038 crate::cmsg_space!(ScmRights(1));
1039 crate::cmsg_space!(TxTime(1));
1040 #[cfg(linux_kernel)]
1041 {
1042 crate::cmsg_space!(ScmCredentials(1));
1043 crate::cmsg_space!(ScmRights(1), ScmCredentials(1), TxTime(1));
1044 crate::cmsg_aligned_space!(ScmRights(1), ScmCredentials(1), TxTime(1));
1045 }
1046 }
1047 }
1048}