Skip to main content

realm_io/linux/
mmsg.rs

1//! Mmsg impl.
2
3use std::task::{Poll, Context};
4use std::io::Result;
5use std::os::unix::io::RawFd;
6
7use crate::AsyncRawIO;
8
9pub use store::SockAddrStore;
10pub use store::{MmsgHdrStore, Const, Mutable};
11pub use store::{MmsgRef, MmsgMutRef};
12pub type MmsgHdr<'a, 'b, 'iov, 'ctrl> = MmsgHdrStore<'a, 'b, 'iov, 'ctrl, Const>;
13pub type MmsgHdrMut<'a, 'b, 'iov, 'ctrl> = MmsgHdrStore<'a, 'b, 'iov, 'ctrl, Mutable>;
14
15#[inline]
16fn sendmpkts<M>(fd: RawFd, pkts: &mut [MmsgHdrStore<'_, '_, '_, '_, M>]) -> i32 {
17    unsafe { libc::sendmmsg(fd, pkts.as_ptr() as *mut _, pkts.len() as u32, 0) }
18}
19
20#[inline]
21fn recvmpkts(fd: RawFd, pkts: &mut [MmsgHdrMut]) -> i32 {
22    unsafe {
23        libc::recvmmsg(
24            fd,
25            pkts.as_mut_ptr() as *mut _,
26            pkts.len() as u32,
27            0,
28            std::ptr::null_mut(),
29        )
30    }
31}
32
33fn poll_sendmpkts<S, M>(
34    sock: &S,
35    cx: &mut Context<'_>,
36    pkts: &mut [MmsgHdrStore<'_, '_, '_, '_, M>],
37) -> Poll<Result<usize>>
38where
39    S: AsyncRawIO + Unpin,
40{
41    sock.poll_write_raw(cx, || sendmpkts(sock.as_raw_fd(), pkts) as isize)
42}
43
44fn poll_recvmpkts<S>(sock: &S, cx: &mut Context<'_>, pkts: &mut [MmsgHdrMut]) -> Poll<Result<usize>>
45where
46    S: AsyncRawIO + Unpin,
47{
48    sock.poll_read_raw(cx, || recvmpkts(sock.as_raw_fd(), pkts) as isize)
49}
50
51/// Send multiple packets.
52pub async fn send_mul_pkts<S, M>(sock: &S, pkts: &mut [MmsgHdrStore<'_, '_, '_, '_, M>]) -> Result<usize>
53where
54    S: AsyncRawIO + Unpin,
55{
56    std::future::poll_fn(move |cx| poll_sendmpkts(sock, cx, pkts)).await
57}
58
59/// Recv multiple packets.
60pub async fn recv_mul_pkts<S>(sock: &S, pkts: &mut [MmsgHdrMut<'_, '_, '_, '_>]) -> Result<usize>
61where
62    S: AsyncRawIO + Unpin,
63{
64    std::future::poll_fn(move |cx| poll_recvmpkts(sock, cx, pkts)).await
65}
66
67mod store {
68    use std::{mem, ptr, slice};
69    use std::marker::PhantomData;
70    use std::io::{IoSlice, IoSliceMut};
71    use std::net::SocketAddr;
72    use socket2::{SockAddr, SockAddrStorage};
73    use libc::{msghdr, mmsghdr};
74
75    /// Marker.
76    #[derive(Debug, Clone, Copy)]
77    pub struct Const {}
78
79    /// Marker.
80    #[derive(Debug, Clone, Copy)]
81    pub struct Mutable {}
82
83    /// # Safety: mmsghdr is POD.
84    unsafe impl<'a, 'b, 'iov, 'ctrl, M> Send for MmsgHdrStore<'a, 'b, 'iov, 'ctrl, M> {}
85
86    /// # Safety: Inner pointers come from references ruled by the borrow-checker,
87    /// thereby mutable pointers which point to the same memory address cant co-exist.
88    ///
89    /// We provide a thin and limited interface that neither [`Const`] nor &[`Mutable`]
90    /// can have mutable access to the internal data, while restriction of mutable access
91    /// behind `&mut`[`Mutable`] will be enforced by the borrow-checker.
92    unsafe impl<'a, 'b, 'iov, 'ctrl, M> Sync for MmsgHdrStore<'a, 'b, 'iov, 'ctrl, M> {}
93
94    /// Represent [`libc::mmsghdr`].
95    #[repr(C)]
96    pub struct MmsgHdrStore<'a, 'b, 'iov, 'ctrl, M> {
97        pub(crate) store: mmsghdr,
98        _type: PhantomData<M>,
99        _lifetime: PhantomData<(&'a (), &'b (), &'iov (), &'ctrl ())>,
100    }
101
102    /// Constant field accessor for [`MmsgHdrStore`].
103    pub struct MmsgRef<'a, 'b, 'iov, 'ctrl, 'this> {
104        addr: &'a SockAddrStore,
105        iovec: &'iov [IoSlice<'b>],
106        control: &'ctrl [u8],
107        flags: &'this i32,
108        nbytes: u32,
109        _lifetime: PhantomData<&'this ()>,
110    }
111
112    /// Mutable field accessor for [`MmsgHdrStore`].
113    pub struct MmsgMutRef<'a, 'b, 'iov, 'ctrl, 'this> {
114        addr: &'a mut SockAddrStore,
115        iovec: &'iov mut [IoSlice<'b>],
116        control: &'ctrl mut [u8],
117        flags: &'this mut i32,
118        nbytes: u32,
119        _lifetime: PhantomData<&'this ()>,
120    }
121
122    #[rustfmt::skip]
123    macro_rules! access_fn {
124        (!ref, $field: ident, $type: ty) => {
125            pub fn $field(&self) -> $type { &self.$field }
126        };
127        (!mut, $field: ident, $type: ty) => {
128            pub fn $field(&mut self) -> $type { &mut self.$field }
129        };
130        (!val, $field: ident, $type: ty) => {
131            pub fn $field(&self) -> $type { self.$field }
132        };
133    }
134
135    impl<'a, 'b, 'iov, 'ctrl, 'this> MmsgRef<'a, 'b, 'iov, 'ctrl, 'this> {
136        access_fn!(!ref, addr, &&'a SockAddrStore);
137        access_fn!(!ref, iovec, &&'iov [IoSlice<'b>]);
138        access_fn!(!ref, control, &&'ctrl [u8]);
139        access_fn!(!ref, flags, &&'this i32);
140        access_fn!(!val, nbytes, u32);
141    }
142
143    impl<'a, 'b, 'iov, 'ctrl, 'this> MmsgMutRef<'a, 'b, 'iov, 'ctrl, 'this> {
144        access_fn!(!mut, addr, &mut &'a mut SockAddrStore);
145        access_fn!(!mut, iovec, &mut &'iov mut [IoSlice<'b>]);
146        access_fn!(!mut, control, &mut &'ctrl mut [u8]);
147        access_fn!(!mut, flags, &mut &'this mut i32);
148        access_fn!(!val, nbytes, u32);
149    }
150
151    #[inline]
152    const unsafe fn make_slice<'a, T>(ptr: *const T, n: usize) -> &'a [T] {
153        use std::ptr::NonNull;
154        let ptr = if n != 0 { ptr } else { NonNull::dangling().as_ptr() };
155        slice::from_raw_parts(ptr, n)
156    }
157
158    #[inline]
159    unsafe fn make_slice_mut<'a, T>(ptr: *mut T, n: usize) -> &'a mut [T] {
160        use std::ptr::NonNull;
161        let ptr = if n != 0 { ptr } else { NonNull::dangling().as_ptr() };
162        slice::from_raw_parts_mut(ptr, n)
163    }
164
165    impl<'a, 'b, 'iov, 'ctrl, M> MmsgHdrStore<'a, 'b, 'iov, 'ctrl, M> {
166        /// New zeroed storage.
167        pub const fn new() -> Self {
168            Self {
169                store: unsafe { mem::zeroed::<mmsghdr>() },
170                _type: PhantomData,
171                _lifetime: PhantomData,
172            }
173        }
174
175        /// Get constant accessor.
176        #[rustfmt::skip]
177        pub fn get_ref<'this>(&'this self) -> MmsgRef<'a, 'b, 'iov, 'ctrl, 'this> {
178            let msghdr {
179                msg_name, msg_namelen: _,
180                msg_iov, msg_iovlen,
181                msg_control, msg_controllen, ..
182            } = self.store.msg_hdr;
183            unsafe { MmsgRef {
184                addr: &*msg_name.cast(),
185                iovec: make_slice(msg_iov as *const _, msg_iovlen as _),
186                control: make_slice(msg_control as *const _, msg_controllen as _),
187                flags: &self.store.msg_hdr.msg_flags,
188                nbytes: self.store.msg_len,
189                _lifetime: PhantomData,
190            }}
191        }
192    }
193
194    impl<'a, 'b, 'iov, 'ctrl, M> Default for MmsgHdrStore<'a, 'b, 'iov, 'ctrl, M> {
195        fn default() -> Self {
196            Self::new()
197        }
198    }
199
200    impl<'a, 'b, 'iov, 'ctrl> MmsgHdrStore<'a, 'b, 'iov, 'ctrl, Const> {
201        /// Set target address.
202        pub const fn with_addr(mut self, addr: &'a SockAddrStore) -> Self {
203            self.store.msg_hdr.msg_name = addr.0.as_ptr() as *mut _;
204            self.store.msg_hdr.msg_namelen = addr.0.len() as _;
205            self
206        }
207
208        /// Set data to send.
209        pub const fn with_iovec(mut self, iov: &'iov [IoSlice<'b>]) -> Self {
210            self.store.msg_hdr.msg_iov = ptr::from_ref(iov) as *mut _;
211            self.store.msg_hdr.msg_iovlen = iov.len() as _;
212            self
213        }
214
215        /// Set control message to send.
216        pub const fn with_control(mut self, ctrl: &'ctrl [u8]) -> Self {
217            self.store.msg_hdr.msg_control = ptr::from_ref(ctrl) as *mut _;
218            self.store.msg_hdr.msg_controllen = ctrl.len() as _;
219            self
220        }
221
222        /// Set message flags to send.
223        pub const fn with_flags(mut self, flags: i32) -> Self {
224            self.store.msg_hdr.msg_flags = flags;
225            self
226        }
227    }
228
229    impl<'a, 'b, 'iov, 'ctrl> MmsgHdrStore<'a, 'b, 'iov, 'ctrl, Mutable> {
230        /// Set storage to accommodate peer address.
231        pub fn with_addr(mut self, addr: &'a mut SockAddrStore) -> Self {
232            self.store.msg_hdr.msg_name = addr.0.as_ptr() as *mut _;
233            self.store.msg_hdr.msg_namelen = addr.0.len() as _;
234            self
235        }
236
237        /// Set storage to receive data.
238        pub fn with_iovec(mut self, iov: &'iov mut [IoSliceMut<'b>]) -> Self {
239            self.store.msg_hdr.msg_iov = ptr::from_mut(iov) as *mut _;
240            self.store.msg_hdr.msg_iovlen = iov.len() as _;
241            self
242        }
243
244        /// Set storage to receive control message.
245        pub fn with_control(mut self, ctrl: &'ctrl mut [u8]) -> Self {
246            self.store.msg_hdr.msg_control = ptr::from_mut(ctrl) as *mut _;
247            self.store.msg_hdr.msg_controllen = ctrl.len() as _;
248            self
249        }
250
251        /// Get mutable accessor.
252        #[rustfmt::skip]
253        pub fn get_mut<'this>(&'this mut self) -> MmsgMutRef<'a, 'b, 'iov, 'ctrl, 'this> {
254            let msghdr {
255                msg_name, msg_namelen: _,
256                msg_iov, msg_iovlen,
257                msg_control, msg_controllen, ..
258            } = self.store.msg_hdr;
259            unsafe { MmsgMutRef {
260                addr: &mut *msg_name.cast(),
261                iovec: make_slice_mut(msg_iov as *mut _, msg_iovlen as _),
262                control: make_slice_mut(msg_control as *mut _, msg_controllen as _),
263                flags: &mut self.store.msg_hdr.msg_flags,
264                nbytes: self.store.msg_len,
265                _lifetime: PhantomData,
266            }}
267        }
268    }
269
270    /// Represent [`libc::sockaddr_storage`].
271    #[derive(Debug, Clone, PartialEq, Eq, Hash)]
272    #[repr(C)]
273    pub struct SockAddrStore(pub(crate) SockAddr);
274
275    impl SockAddrStore {
276        /// New zeroed storage.
277        pub fn new() -> Self {
278            let store = SockAddrStorage::zeroed();
279            let sizeof = store.size_of();
280            Self(unsafe { SockAddr::new(store, sizeof) })
281        }
282    }
283
284    impl Default for SockAddrStore {
285        fn default() -> Self {
286            Self::new()
287        }
288    }
289
290    impl<T> From<T> for SockAddrStore
291    where
292        SockAddr: From<T>,
293    {
294        fn from(addr: T) -> Self {
295            Self(addr.into())
296        }
297    }
298
299    impl From<SockAddrStore> for SocketAddr {
300        fn from(store: SockAddrStore) -> Self {
301            store.0.as_socket().unwrap()
302        }
303    }
304}