1use 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
51pub 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
59pub 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 #[derive(Debug, Clone, Copy)]
77 pub struct Const {}
78
79 #[derive(Debug, Clone, Copy)]
81 pub struct Mutable {}
82
83 unsafe impl<'a, 'b, 'iov, 'ctrl, M> Send for MmsgHdrStore<'a, 'b, 'iov, 'ctrl, M> {}
85
86 unsafe impl<'a, 'b, 'iov, 'ctrl, M> Sync for MmsgHdrStore<'a, 'b, 'iov, 'ctrl, M> {}
93
94 #[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 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 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 pub const fn new() -> Self {
168 Self {
169 store: unsafe { mem::zeroed::<mmsghdr>() },
170 _type: PhantomData,
171 _lifetime: PhantomData,
172 }
173 }
174
175 #[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 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 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 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 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 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 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 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 #[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 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
272 #[repr(C)]
273 pub struct SockAddrStore(pub(crate) SockAddr);
274
275 impl SockAddrStore {
276 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}