dope_core/io/socket/msg/
mod.rs1use core::{marker, ptr};
2
3use crate::{
4 backend,
5 io::{socket, transfer},
6};
7
8pub mod raw;
9
10pub const MAX_IOVECS: usize = <backend::Backend as backend::Socket>::MAX_IOVECS;
12
13#[derive(Clone, Copy, Debug)]
17#[repr(transparent)]
18pub struct Iovec {
19 raw: libc::iovec,
20}
21
22impl Iovec {
23 #[must_use]
24 pub const fn empty() -> Self {
25 Self {
26 raw: libc::iovec {
27 iov_base: ptr::null_mut(),
28 iov_len: 0,
29 },
30 }
31 }
32
33 fn from_slice(buf: &[u8]) -> Self {
34 Self {
35 raw: libc::iovec {
36 iov_base: buf.as_ptr().cast_mut().cast(),
37 iov_len: buf.len(),
38 },
39 }
40 }
41
42 #[must_use]
43 pub fn len(&self) -> usize {
44 self.raw.iov_len
45 }
46
47 #[must_use]
48 pub fn is_empty(&self) -> bool {
49 self.raw.iov_len == 0
50 }
51}
52
53#[derive(Debug)]
57#[repr(transparent)]
58pub struct Header {
59 raw: libc::msghdr,
60}
61
62impl Header {
63 #[must_use]
64 pub const fn new() -> Self {
65 Self {
66 raw: libc::msghdr {
67 msg_name: ptr::null_mut(),
68 msg_namelen: 0,
69 msg_iov: ptr::null_mut(),
70 msg_iovlen: 0,
71 msg_control: ptr::null_mut(),
72 msg_controllen: 0,
73 msg_flags: 0,
74 },
75 }
76 }
77
78 fn bind_iovs(&mut self, iovs: &[Iovec]) {
79 self.raw.msg_iov = if iovs.is_empty() {
80 ptr::null_mut()
81 } else {
82 iovs.as_ptr().cast_mut().cast()
83 };
84 self.raw.msg_iovlen = iovs.len() as _;
85 }
86}
87
88impl Default for Header {
89 fn default() -> Self {
90 Self::new()
91 }
92}
93
94#[derive(Clone, Copy)]
96#[repr(transparent)]
97pub struct Message<'a> {
98 header: *const libc::msghdr,
99 graph: marker::PhantomData<&'a Header>,
100}
101
102impl Message<'_> {
103 pub(crate) fn raw(self) -> *const libc::msghdr {
104 self.header
105 }
106}
107
108pub struct Vectored<'a> {
110 message: Message<'a>,
111 iovs: &'a [Iovec],
112 bytes: transfer::Len,
113}
114
115impl<'a> Vectored<'a> {
116 #[must_use]
117 pub fn message(&self) -> Message<'a> {
118 self.message
119 }
120
121 pub fn iter(&self) -> impl Iterator<Item = &'a [u8]> + '_ {
122 let iovs: &'a [Iovec] = self.iovs;
123 iovs.iter().map(raw::Project::slice)
124 }
125
126 #[must_use]
127 pub fn bytes(&self) -> usize {
128 self.bytes.into_usize()
129 }
130
131 #[must_use]
132 pub fn is_empty(&self) -> bool {
133 self.bytes == transfer::Len::ZERO
134 }
135}
136
137impl<'a> Vectored<'a> {
138 fn from_parts(header: &'a mut Header, iovs: &'a [Iovec], bytes: transfer::Len) -> Self {
139 Self {
140 message: Message {
141 header: ptr::from_ref(&header.raw),
142 graph: marker::PhantomData,
143 },
144 iovs,
145 bytes,
146 }
147 }
148}
149
150pub struct Parts<'a, const N: usize> {
152 slices: [&'a [u8]; N],
153 bytes: transfer::Len,
154}
155
156impl<'a, const N: usize> Parts<'a, N> {
157 pub fn try_new(slices: [&'a [u8]; N]) -> Option<Self> {
158 if N > MAX_IOVECS {
159 return None;
160 }
161 let mut bytes = transfer::Len::ZERO;
162 for slice in &slices {
163 bytes = bytes.checked_add(slice.len())?;
164 }
165 Some(Self { slices, bytes })
166 }
167}
168
169impl<'a> Parts<'a, 1> {
170 #[must_use]
171 pub fn single(part: raw::Part<'a>) -> Self {
172 let (slice, bytes) = part.into_parts();
173 Self {
174 slices: [slice],
175 bytes,
176 }
177 }
178}
179
180impl<'a> Parts<'a, 2> {
181 #[must_use]
182 pub fn prefixes(limit: transfer::Len, sources: [&'a [u8]; 2]) -> Self {
183 let first_len = sources[0].len().min(limit.into_usize());
184 let second_len = sources[1].len().min(limit.into_usize() - first_len);
185 let slices = [&sources[0][..first_len], &sources[1][..second_len]];
186 Self {
187 slices,
188 bytes: transfer::Len::from_bounded(first_len + second_len),
189 }
190 }
191}
192
193pub struct Builder<'a> {
211 header: &'a mut Header,
212 graph: marker::PhantomData<&'a Header>,
213}
214
215impl<'a> Builder<'a> {
216 pub fn new(header: &'a mut Header) -> Self {
217 *header = Header::new();
218 Self {
219 header,
220 graph: marker::PhantomData,
221 }
222 }
223
224 pub fn name(&mut self, addr: &'a socket::raw::Inet) {
225 self.header.raw.msg_name = addr.ptr().cast_mut().cast();
226 self.header.raw.msg_namelen = addr.socklen();
227 }
228
229 #[doc(hidden)]
231 pub fn control(&mut self, control: &'a [u8]) {
232 self.header.raw.msg_control = control.as_ptr().cast_mut().cast();
233 self.header.raw.msg_controllen = control.len() as _;
234 }
235
236 #[must_use]
237 pub fn finish<const N: usize>(
238 self,
239 iovs: &'a mut [Iovec; N],
240 parts: Parts<'a, N>,
241 ) -> Vectored<'a> {
242 let Parts { slices, bytes } = parts;
243 *iovs = slices.map(Iovec::from_slice);
244 let iovs: &'a [Iovec] = iovs;
245 self.header.bind_iovs(iovs);
246 Vectored {
247 message: Message {
248 header: ptr::from_ref(&self.header.raw),
249 graph: self.graph,
250 },
251 iovs,
252 bytes,
253 }
254 }
255}
256
257const _: () = assert!(size_of::<Iovec>() == size_of::<libc::iovec>());
258const _: () = assert!(align_of::<Iovec>() == align_of::<libc::iovec>());
259const _: () = assert!(size_of::<Header>() == size_of::<libc::msghdr>());
260const _: () = assert!(align_of::<Header>() == align_of::<libc::msghdr>());
261const _: () = assert!(size_of::<Message<'static>>() == size_of::<*const libc::msghdr>());
262const _: () = assert!(MAX_IOVECS >= 2);