Skip to main content

compio_io/ancillary/
mod.rs

1//! Ancillary data (control message) support for connected streams.
2//!
3//! Ancillary messages are used to pass out-of-band information such as file
4//! descriptors (Unix domain sockets), credentials, or kTLS record types.
5//!
6//! # Types
7//!
8//! - [`AncillaryRef`]: A reference to a single ancillary data entry.
9//! - [`AncillaryIter`]: An iterator over a buffer of ancillary messages.
10//! - [`AncillaryBuilder`]: A builder for constructing ancillary messages into a
11//!   caller-supplied send buffer.
12//! - [`AncillaryBuf`]: A fixed-size, properly aligned stack buffer for
13//!   ancillary data
14
15use std::{
16    marker::PhantomData,
17    mem::MaybeUninit,
18    ops::{Deref, DerefMut},
19};
20
21use compio_buf::{IoBuf, IoBufMut, SetLen};
22#[cfg(windows)]
23use windows_sys::Win32::Networking::WinSock;
24
25cfg_if::cfg_if! {
26    if #[cfg(windows)] {
27        #[path = "windows.rs"]
28        mod sys;
29    } else if #[cfg(unix)] {
30        #[path = "unix.rs"]
31        mod sys;
32    }
33}
34
35/// Reference to an ancillary (control) message.
36pub struct AncillaryRef<'a>(sys::CMsgRef<'a>);
37
38impl AncillaryRef<'_> {
39    /// Returns the level of the control message.
40    pub fn level(&self) -> i32 {
41        self.0.level()
42    }
43
44    /// Returns the type of the control message.
45    pub fn ty(&self) -> i32 {
46        self.0.ty()
47    }
48
49    /// Returns the length of the control message.
50    #[allow(clippy::len_without_is_empty)]
51    pub fn len(&self) -> usize {
52        self.0.len() as _
53    }
54
55    /// Returns a reference to the data of the control message.
56    ///
57    /// # Safety
58    ///
59    /// The data part must be properly aligned and contains an initialized
60    /// instance of `T`.
61    pub unsafe fn data<T>(&self) -> &T {
62        unsafe { self.0.data() }
63    }
64}
65
66/// An iterator for ancillary (control) messages.
67pub struct AncillaryIter<'a> {
68    inner: sys::CMsgIter,
69    _p: PhantomData<&'a ()>,
70}
71
72impl<'a> AncillaryIter<'a> {
73    /// Create [`AncillaryIter`] with the given buffer.
74    ///
75    /// # Panics
76    ///
77    /// This function will panic if the buffer is too short or not properly
78    /// aligned.
79    ///
80    /// # Safety
81    ///
82    /// The buffer should contain valid control messages.
83    pub unsafe fn new(buffer: &'a [u8]) -> Self {
84        Self {
85            inner: sys::CMsgIter::new(buffer.as_ptr(), buffer.len()),
86            _p: PhantomData,
87        }
88    }
89}
90
91impl<'a> Iterator for AncillaryIter<'a> {
92    type Item = AncillaryRef<'a>;
93
94    fn next(&mut self) -> Option<Self::Item> {
95        unsafe {
96            let cmsg = self.inner.current();
97            self.inner.next();
98            cmsg.map(AncillaryRef)
99        }
100    }
101}
102
103/// Helper to construct ancillary (control) messages.
104pub struct AncillaryBuilder<'a> {
105    inner: sys::CMsgIter,
106    len: usize,
107    _p: PhantomData<&'a mut ()>,
108}
109
110impl<'a> AncillaryBuilder<'a> {
111    /// Create [`AncillaryBuilder`] with the given buffer. The buffer will be
112    /// zeroed on creation.
113    ///
114    /// # Panics
115    ///
116    /// This function will panic if the buffer is too short or not properly
117    /// aligned.
118    pub fn new(buffer: &'a mut [MaybeUninit<u8>]) -> Self {
119        // TODO: optimize zeroing
120        buffer.fill(MaybeUninit::new(0));
121        Self {
122            inner: sys::CMsgIter::new(buffer.as_ptr().cast(), buffer.len()),
123            len: 0,
124            _p: PhantomData,
125        }
126    }
127
128    /// Finishes building, returns length of the control message.
129    pub fn finish(self) -> usize {
130        self.len
131    }
132
133    /// Try to append a control message entry into the buffer. If the buffer
134    /// does not have enough space or is not properly aligned with the value
135    /// type, returns `None`.
136    pub fn try_push<T>(&mut self, level: i32, ty: i32, value: T) -> Option<()> {
137        if !self.inner.is_aligned::<T>() || !self.inner.is_space_enough::<T>() {
138            return None;
139        }
140
141        // SAFETY: the buffer is zeroed and the pointer is valid and aligned
142        unsafe {
143            let mut cmsg = self.inner.current_mut()?;
144            cmsg.set_level(level);
145            cmsg.set_ty(ty);
146            self.len += cmsg.set_data(value);
147
148            self.inner.next();
149        }
150
151        Some(())
152    }
153}
154
155/// A fixed-size, stack-allocated buffer for ancillary (control) messages.
156///
157/// Properly aligned for the platform's control message header type
158/// (`cmsghdr` on Unix, `CMSGHDR` on Windows), so it can be passed directly
159/// to [`AncillaryIter`] and [`AncillaryBuilder`].
160pub struct AncillaryBuf<const N: usize> {
161    inner: [u8; N],
162    len: usize,
163    #[cfg(unix)]
164    _align: [libc::cmsghdr; 0],
165    #[cfg(windows)]
166    _align: [WinSock::CMSGHDR; 0],
167}
168
169impl<const N: usize> AncillaryBuf<N> {
170    /// Create a new zeroed [`AncillaryBuf`].
171    pub fn new() -> Self {
172        Self {
173            inner: [0u8; N],
174            len: 0,
175            _align: [],
176        }
177    }
178}
179
180impl<const N: usize> Default for AncillaryBuf<N> {
181    fn default() -> Self {
182        Self::new()
183    }
184}
185
186impl<const N: usize> IoBuf for AncillaryBuf<N> {
187    fn as_init(&self) -> &[u8] {
188        &self.inner[..self.len]
189    }
190}
191
192impl<const N: usize> SetLen for AncillaryBuf<N> {
193    unsafe fn set_len(&mut self, len: usize) {
194        debug_assert!(len <= N);
195        self.len = len;
196    }
197}
198
199impl<const N: usize> IoBufMut for AncillaryBuf<N> {
200    fn as_uninit(&mut self) -> &mut [MaybeUninit<u8>] {
201        self.inner.as_uninit()
202    }
203}
204
205impl<const N: usize> Deref for AncillaryBuf<N> {
206    type Target = [u8];
207
208    fn deref(&self) -> &Self::Target {
209        &self.inner[0..self.len]
210    }
211}
212
213impl<const N: usize> DerefMut for AncillaryBuf<N> {
214    fn deref_mut(&mut self) -> &mut Self::Target {
215        &mut self.inner[0..self.len]
216    }
217}