]>
Commit | Line | Data |
---|---|---|
fe692bf9 FG |
1 | //! [`recvmsg`], [`sendmsg`], and related functions. |
2 | ||
3 | #![allow(unsafe_code)] | |
4 | ||
5 | use crate::backend::{self, c}; | |
6 | use crate::fd::{AsFd, BorrowedFd, OwnedFd}; | |
7 | use crate::io::{self, IoSlice, IoSliceMut}; | |
ed00b5ec FG |
8 | #[cfg(linux_kernel)] |
9 | use crate::net::UCred; | |
fe692bf9 FG |
10 | |
11 | use core::iter::FusedIterator; | |
12 | use core::marker::PhantomData; | |
ed00b5ec FG |
13 | use core::mem::{align_of, size_of, size_of_val, take}; |
14 | #[cfg(linux_kernel)] | |
15 | use core::ptr::addr_of; | |
fe692bf9 FG |
16 | use core::{ptr, slice}; |
17 | ||
18 | use super::{RecvFlags, SendFlags, SocketAddrAny, SocketAddrV4, SocketAddrV6}; | |
19 | ||
20 | /// Macro for defining the amount of space used by CMSGs. | |
21 | #[macro_export] | |
22 | macro_rules! cmsg_space { | |
23 | // Base Rules | |
24 | (ScmRights($len:expr)) => { | |
25 | $crate::net::__cmsg_space( | |
26 | $len * ::core::mem::size_of::<$crate::fd::BorrowedFd<'static>>(), | |
27 | ) | |
28 | }; | |
ed00b5ec FG |
29 | (ScmCredentials($len:expr)) => { |
30 | $crate::net::__cmsg_space( | |
31 | $len * ::core::mem::size_of::<$crate::net::UCred>(), | |
32 | ) | |
33 | }; | |
fe692bf9 FG |
34 | |
35 | // Combo Rules | |
36 | (($($($x:tt)*),+)) => { | |
37 | $( | |
38 | cmsg_space!($($x)*) + | |
39 | )+ | |
40 | 0 | |
41 | }; | |
42 | } | |
43 | ||
44 | #[doc(hidden)] | |
ed00b5ec FG |
45 | pub const fn __cmsg_space(len: usize) -> usize { |
46 | // Add `align_of::<c::cmsghdr>()` so that we can align the user-provided | |
47 | // `&[u8]` to the required alignment boundary. | |
48 | let len = len + align_of::<c::cmsghdr>(); | |
49 | ||
50 | // Convert `len` to `u32` for `CMSG_SPACE`. This would be `try_into()` if | |
51 | // we could call that in a `const fn`. | |
52 | let converted_len = len as u32; | |
53 | if converted_len as usize != len { | |
54 | unreachable!(); // `CMSG_SPACE` size overflow | |
55 | } | |
56 | ||
57 | unsafe { c::CMSG_SPACE(converted_len) as usize } | |
fe692bf9 FG |
58 | } |
59 | ||
60 | /// Ancillary message for [`sendmsg`], [`sendmsg_v4`], [`sendmsg_v6`], | |
61 | /// [`sendmsg_unix`], and [`sendmsg_any`]. | |
62 | #[non_exhaustive] | |
63 | pub enum SendAncillaryMessage<'slice, 'fd> { | |
64 | /// Send file descriptors. | |
ed00b5ec | 65 | #[doc(alias = "SCM_RIGHTS")] |
fe692bf9 | 66 | ScmRights(&'slice [BorrowedFd<'fd>]), |
ed00b5ec FG |
67 | /// Send process credentials. |
68 | #[cfg(linux_kernel)] | |
69 | #[doc(alias = "SCM_CREDENTIAL")] | |
70 | ScmCredentials(UCred), | |
fe692bf9 FG |
71 | } |
72 | ||
73 | impl SendAncillaryMessage<'_, '_> { | |
74 | /// Get the maximum size of an ancillary message. | |
75 | /// | |
76 | /// This can be helpful in determining the size of the buffer you allocate. | |
ed00b5ec FG |
77 | pub const fn size(&self) -> usize { |
78 | match self { | |
79 | Self::ScmRights(slice) => cmsg_space!(ScmRights(slice.len())), | |
80 | #[cfg(linux_kernel)] | |
81 | Self::ScmCredentials(_) => cmsg_space!(ScmCredentials(1)), | |
fe692bf9 FG |
82 | } |
83 | } | |
84 | } | |
85 | ||
86 | /// Ancillary message for [`recvmsg`]. | |
87 | #[non_exhaustive] | |
88 | pub enum RecvAncillaryMessage<'a> { | |
89 | /// Received file descriptors. | |
ed00b5ec | 90 | #[doc(alias = "SCM_RIGHTS")] |
fe692bf9 | 91 | ScmRights(AncillaryIter<'a, OwnedFd>), |
ed00b5ec FG |
92 | /// Received process credentials. |
93 | #[cfg(linux_kernel)] | |
94 | #[doc(alias = "SCM_CREDENTIALS")] | |
95 | ScmCredentials(UCred), | |
fe692bf9 FG |
96 | } |
97 | ||
ed00b5ec FG |
98 | /// Buffer for sending ancillary messages with [`sendmsg`], [`sendmsg_v4`], |
99 | /// [`sendmsg_v6`], [`sendmsg_unix`], and [`sendmsg_any`]. | |
fe692bf9 FG |
100 | pub struct SendAncillaryBuffer<'buf, 'slice, 'fd> { |
101 | /// Raw byte buffer for messages. | |
102 | buffer: &'buf mut [u8], | |
103 | ||
104 | /// The amount of the buffer that is used. | |
105 | length: usize, | |
106 | ||
107 | /// Phantom data for lifetime of `&'slice [BorrowedFd<'fd>]`. | |
108 | _phantom: PhantomData<&'slice [BorrowedFd<'fd>]>, | |
109 | } | |
110 | ||
111 | impl<'buf> From<&'buf mut [u8]> for SendAncillaryBuffer<'buf, '_, '_> { | |
112 | fn from(buffer: &'buf mut [u8]) -> Self { | |
113 | Self::new(buffer) | |
114 | } | |
115 | } | |
116 | ||
117 | impl Default for SendAncillaryBuffer<'_, '_, '_> { | |
118 | fn default() -> Self { | |
ed00b5ec FG |
119 | Self { |
120 | buffer: &mut [], | |
121 | length: 0, | |
122 | _phantom: PhantomData, | |
123 | } | |
fe692bf9 FG |
124 | } |
125 | } | |
126 | ||
127 | impl<'buf, 'slice, 'fd> SendAncillaryBuffer<'buf, 'slice, 'fd> { | |
128 | /// Create a new, empty `SendAncillaryBuffer` from a raw byte buffer. | |
ed00b5ec | 129 | #[inline] |
fe692bf9 FG |
130 | pub fn new(buffer: &'buf mut [u8]) -> Self { |
131 | Self { | |
ed00b5ec | 132 | buffer: align_for_cmsghdr(buffer), |
fe692bf9 FG |
133 | length: 0, |
134 | _phantom: PhantomData, | |
135 | } | |
136 | } | |
137 | ||
138 | /// Returns a pointer to the message data. | |
139 | pub(crate) fn as_control_ptr(&mut self) -> *mut u8 { | |
781aab86 FG |
140 | // When the length is zero, we may be using a `&[]` address, which may |
141 | // be an invalid but non-null pointer, and on some platforms, that | |
add651ee FG |
142 | // causes `sendmsg` to fail with `EFAULT` or `EINVAL` |
143 | #[cfg(not(linux_kernel))] | |
144 | if self.length == 0 { | |
145 | return core::ptr::null_mut(); | |
fe692bf9 | 146 | } |
add651ee FG |
147 | |
148 | self.buffer.as_mut_ptr() | |
fe692bf9 FG |
149 | } |
150 | ||
151 | /// Returns the length of the message data. | |
152 | pub(crate) fn control_len(&self) -> usize { | |
153 | self.length | |
154 | } | |
155 | ||
156 | /// Delete all messages from the buffer. | |
157 | pub fn clear(&mut self) { | |
158 | self.length = 0; | |
159 | } | |
160 | ||
161 | /// Add an ancillary message to the buffer. | |
162 | /// | |
163 | /// Returns `true` if the message was added successfully. | |
164 | pub fn push(&mut self, msg: SendAncillaryMessage<'slice, 'fd>) -> bool { | |
165 | match msg { | |
166 | SendAncillaryMessage::ScmRights(fds) => { | |
167 | let fds_bytes = | |
168 | unsafe { slice::from_raw_parts(fds.as_ptr().cast::<u8>(), size_of_val(fds)) }; | |
169 | self.push_ancillary(fds_bytes, c::SOL_SOCKET as _, c::SCM_RIGHTS as _) | |
170 | } | |
ed00b5ec FG |
171 | #[cfg(linux_kernel)] |
172 | SendAncillaryMessage::ScmCredentials(ucred) => { | |
173 | let ucred_bytes = unsafe { | |
174 | slice::from_raw_parts(addr_of!(ucred).cast::<u8>(), size_of_val(&ucred)) | |
175 | }; | |
176 | self.push_ancillary(ucred_bytes, c::SOL_SOCKET as _, c::SCM_CREDENTIALS as _) | |
177 | } | |
fe692bf9 FG |
178 | } |
179 | } | |
180 | ||
181 | /// Pushes an ancillary message to the buffer. | |
182 | fn push_ancillary(&mut self, source: &[u8], cmsg_level: c::c_int, cmsg_type: c::c_int) -> bool { | |
183 | macro_rules! leap { | |
184 | ($e:expr) => {{ | |
185 | match ($e) { | |
186 | Some(x) => x, | |
187 | None => return false, | |
188 | } | |
189 | }}; | |
190 | } | |
191 | ||
192 | // Calculate the length of the message. | |
193 | let source_len = leap!(u32::try_from(source.len()).ok()); | |
194 | ||
195 | // Calculate the new length of the buffer. | |
196 | let additional_space = unsafe { c::CMSG_SPACE(source_len) }; | |
197 | let new_length = leap!(self.length.checked_add(additional_space as usize)); | |
198 | let buffer = leap!(self.buffer.get_mut(..new_length)); | |
199 | ||
200 | // Fill the new part of the buffer with zeroes. | |
201 | buffer[self.length..new_length].fill(0); | |
202 | self.length = new_length; | |
203 | ||
204 | // Get the last header in the buffer. | |
205 | let last_header = leap!(messages::Messages::new(buffer).last()); | |
206 | ||
207 | // Set the header fields. | |
208 | last_header.cmsg_len = unsafe { c::CMSG_LEN(source_len) } as _; | |
209 | last_header.cmsg_level = cmsg_level; | |
210 | last_header.cmsg_type = cmsg_type; | |
211 | ||
212 | // Get the pointer to the payload and copy the data. | |
213 | unsafe { | |
214 | let payload = c::CMSG_DATA(last_header); | |
215 | ptr::copy_nonoverlapping(source.as_ptr(), payload, source_len as _); | |
216 | } | |
217 | ||
218 | true | |
219 | } | |
220 | } | |
221 | ||
222 | impl<'slice, 'fd> Extend<SendAncillaryMessage<'slice, 'fd>> | |
223 | for SendAncillaryBuffer<'_, 'slice, 'fd> | |
224 | { | |
225 | fn extend<T: IntoIterator<Item = SendAncillaryMessage<'slice, 'fd>>>(&mut self, iter: T) { | |
226 | // TODO: This could be optimized to add every message in one go. | |
227 | iter.into_iter().all(|msg| self.push(msg)); | |
228 | } | |
229 | } | |
230 | ||
ed00b5ec FG |
231 | /// Buffer for receiving ancillary messages with [`recvmsg`]. |
232 | #[derive(Default)] | |
fe692bf9 FG |
233 | pub struct RecvAncillaryBuffer<'buf> { |
234 | /// Raw byte buffer for messages. | |
235 | buffer: &'buf mut [u8], | |
236 | ||
237 | /// The portion of the buffer we've read from already. | |
238 | read: usize, | |
239 | ||
240 | /// The amount of the buffer that is used. | |
241 | length: usize, | |
242 | } | |
243 | ||
244 | impl<'buf> From<&'buf mut [u8]> for RecvAncillaryBuffer<'buf> { | |
245 | fn from(buffer: &'buf mut [u8]) -> Self { | |
246 | Self::new(buffer) | |
247 | } | |
248 | } | |
249 | ||
fe692bf9 FG |
250 | impl<'buf> RecvAncillaryBuffer<'buf> { |
251 | /// Create a new, empty `RecvAncillaryBuffer` from a raw byte buffer. | |
ed00b5ec | 252 | #[inline] |
fe692bf9 FG |
253 | pub fn new(buffer: &'buf mut [u8]) -> Self { |
254 | Self { | |
ed00b5ec | 255 | buffer: align_for_cmsghdr(buffer), |
fe692bf9 FG |
256 | read: 0, |
257 | length: 0, | |
258 | } | |
259 | } | |
260 | ||
261 | /// Returns a pointer to the message data. | |
262 | pub(crate) fn as_control_ptr(&mut self) -> *mut u8 { | |
781aab86 FG |
263 | // When the length is zero, we may be using a `&[]` address, which may |
264 | // be an invalid but non-null pointer, and on some platforms, that | |
add651ee FG |
265 | // causes `sendmsg` to fail with `EFAULT` or `EINVAL` |
266 | #[cfg(not(linux_kernel))] | |
267 | if self.buffer.is_empty() { | |
268 | return core::ptr::null_mut(); | |
269 | } | |
270 | ||
fe692bf9 FG |
271 | self.buffer.as_mut_ptr() |
272 | } | |
273 | ||
274 | /// Returns the length of the message data. | |
275 | pub(crate) fn control_len(&self) -> usize { | |
276 | self.buffer.len() | |
277 | } | |
278 | ||
279 | /// Set the length of the message data. | |
280 | /// | |
281 | /// # Safety | |
282 | /// | |
283 | /// The buffer must be filled with valid message data. | |
284 | pub(crate) unsafe fn set_control_len(&mut self, len: usize) { | |
285 | self.length = len; | |
286 | self.read = 0; | |
287 | } | |
288 | ||
289 | /// Delete all messages from the buffer. | |
290 | pub(crate) fn clear(&mut self) { | |
291 | self.drain().for_each(drop); | |
292 | } | |
293 | ||
294 | /// Drain all messages from the buffer. | |
295 | pub fn drain(&mut self) -> AncillaryDrain<'_> { | |
296 | AncillaryDrain { | |
297 | messages: messages::Messages::new(&mut self.buffer[self.read..][..self.length]), | |
298 | read: &mut self.read, | |
299 | length: &mut self.length, | |
300 | } | |
301 | } | |
302 | } | |
303 | ||
304 | impl Drop for RecvAncillaryBuffer<'_> { | |
305 | fn drop(&mut self) { | |
306 | self.clear(); | |
307 | } | |
308 | } | |
309 | ||
ed00b5ec FG |
310 | /// Return a slice of `buffer` starting at the first `cmsghdr` alignment |
311 | /// boundary. | |
312 | #[inline] | |
313 | fn align_for_cmsghdr(buffer: &mut [u8]) -> &mut [u8] { | |
314 | let align = align_of::<c::cmsghdr>(); | |
315 | let addr = buffer.as_ptr() as usize; | |
316 | let adjusted = (addr + (align - 1)) & align.wrapping_neg(); | |
317 | &mut buffer[adjusted - addr..] | |
318 | } | |
319 | ||
320 | /// An iterator that drains messages from a [`RecvAncillaryBuffer`]. | |
fe692bf9 FG |
321 | pub struct AncillaryDrain<'buf> { |
322 | /// Inner iterator over messages. | |
323 | messages: messages::Messages<'buf>, | |
324 | ||
325 | /// Increment the number of messages we've read. | |
326 | read: &'buf mut usize, | |
327 | ||
328 | /// Decrement the total length. | |
329 | length: &'buf mut usize, | |
330 | } | |
331 | ||
332 | impl<'buf> AncillaryDrain<'buf> { | |
ed00b5ec | 333 | /// A closure that converts a message into a [`RecvAncillaryMessage`]. |
fe692bf9 FG |
334 | fn cvt_msg( |
335 | read: &mut usize, | |
336 | length: &mut usize, | |
337 | msg: &c::cmsghdr, | |
338 | ) -> Option<RecvAncillaryMessage<'buf>> { | |
339 | unsafe { | |
ed00b5ec | 340 | // Advance the `read` pointer. |
fe692bf9 FG |
341 | let msg_len = msg.cmsg_len as usize; |
342 | *read += msg_len; | |
343 | *length -= msg_len; | |
344 | ||
345 | // Get a pointer to the payload. | |
346 | let payload = c::CMSG_DATA(msg); | |
347 | let payload_len = msg.cmsg_len as usize - c::CMSG_LEN(0) as usize; | |
348 | ||
349 | // Get a mutable slice of the payload. | |
350 | let payload: &'buf mut [u8] = slice::from_raw_parts_mut(payload, payload_len); | |
351 | ||
352 | // Determine what type it is. | |
353 | let (level, msg_type) = (msg.cmsg_level, msg.cmsg_type); | |
354 | match (level as _, msg_type as _) { | |
355 | (c::SOL_SOCKET, c::SCM_RIGHTS) => { | |
356 | // Create an iterator that reads out the file descriptors. | |
357 | let fds = AncillaryIter::new(payload); | |
358 | ||
359 | Some(RecvAncillaryMessage::ScmRights(fds)) | |
360 | } | |
ed00b5ec FG |
361 | #[cfg(linux_kernel)] |
362 | (c::SOL_SOCKET, c::SCM_CREDENTIALS) => { | |
363 | if payload_len >= size_of::<UCred>() { | |
364 | let ucred = payload.as_ptr().cast::<UCred>().read_unaligned(); | |
365 | Some(RecvAncillaryMessage::ScmCredentials(ucred)) | |
366 | } else { | |
367 | None | |
368 | } | |
369 | } | |
fe692bf9 FG |
370 | _ => None, |
371 | } | |
372 | } | |
373 | } | |
374 | } | |
375 | ||
376 | impl<'buf> Iterator for AncillaryDrain<'buf> { | |
377 | type Item = RecvAncillaryMessage<'buf>; | |
378 | ||
379 | fn next(&mut self) -> Option<Self::Item> { | |
380 | let read = &mut self.read; | |
381 | let length = &mut self.length; | |
382 | self.messages.find_map(|ev| Self::cvt_msg(read, length, ev)) | |
383 | } | |
384 | ||
385 | fn size_hint(&self) -> (usize, Option<usize>) { | |
386 | let (_, max) = self.messages.size_hint(); | |
387 | (0, max) | |
388 | } | |
389 | ||
390 | fn fold<B, F>(self, init: B, f: F) -> B | |
391 | where | |
392 | Self: Sized, | |
393 | F: FnMut(B, Self::Item) -> B, | |
394 | { | |
395 | let read = self.read; | |
396 | let length = self.length; | |
397 | self.messages | |
398 | .filter_map(|ev| Self::cvt_msg(read, length, ev)) | |
399 | .fold(init, f) | |
400 | } | |
401 | ||
402 | fn count(self) -> usize { | |
403 | let read = self.read; | |
404 | let length = self.length; | |
405 | self.messages | |
406 | .filter_map(|ev| Self::cvt_msg(read, length, ev)) | |
407 | .count() | |
408 | } | |
409 | ||
410 | fn last(self) -> Option<Self::Item> | |
411 | where | |
412 | Self: Sized, | |
413 | { | |
414 | let read = self.read; | |
415 | let length = self.length; | |
416 | self.messages | |
417 | .filter_map(|ev| Self::cvt_msg(read, length, ev)) | |
418 | .last() | |
419 | } | |
420 | ||
421 | fn collect<B: FromIterator<Self::Item>>(self) -> B | |
422 | where | |
423 | Self: Sized, | |
424 | { | |
425 | let read = self.read; | |
426 | let length = self.length; | |
427 | self.messages | |
428 | .filter_map(|ev| Self::cvt_msg(read, length, ev)) | |
429 | .collect() | |
430 | } | |
431 | } | |
432 | ||
433 | impl FusedIterator for AncillaryDrain<'_> {} | |
434 | ||
435 | /// `sendmsg(msghdr)`—Sends a message on a socket. | |
436 | /// | |
437 | /// # References | |
438 | /// - [POSIX] | |
439 | /// - [Linux] | |
440 | /// - [Apple] | |
441 | /// - [FreeBSD] | |
442 | /// - [NetBSD] | |
443 | /// - [OpenBSD] | |
444 | /// - [DragonFly BSD] | |
445 | /// - [illumos] | |
446 | /// | |
447 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendmsg.html | |
448 | /// [Linux]: https://man7.org/linux/man-pages/man2/sendmsg.2.html | |
449 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendmsg.2.html | |
450 | /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendmsg&sektion=2 | |
451 | /// [NetBSD]: https://man.netbsd.org/sendmsg.2 | |
452 | /// [OpenBSD]: https://man.openbsd.org/sendmsg.2 | |
453 | /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendmsg§ion=2 | |
454 | /// [illumos]: https://illumos.org/man/3SOCKET/sendmsg | |
455 | #[inline] | |
456 | pub fn sendmsg( | |
457 | socket: impl AsFd, | |
458 | iov: &[IoSlice<'_>], | |
459 | control: &mut SendAncillaryBuffer<'_, '_, '_>, | |
460 | flags: SendFlags, | |
461 | ) -> io::Result<usize> { | |
462 | backend::net::syscalls::sendmsg(socket.as_fd(), iov, control, flags) | |
463 | } | |
464 | ||
465 | /// `sendmsg(msghdr)`—Sends a message on a socket to a specific IPv4 address. | |
466 | /// | |
467 | /// # References | |
468 | /// - [POSIX] | |
469 | /// - [Linux] | |
470 | /// - [Apple] | |
471 | /// - [FreeBSD] | |
472 | /// - [NetBSD] | |
473 | /// - [OpenBSD] | |
474 | /// - [DragonFly BSD] | |
475 | /// - [illumos] | |
476 | /// | |
477 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendmsg.html | |
478 | /// [Linux]: https://man7.org/linux/man-pages/man2/sendmsg.2.html | |
479 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendmsg.2.html | |
480 | /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendmsg&sektion=2 | |
481 | /// [NetBSD]: https://man.netbsd.org/sendmsg.2 | |
482 | /// [OpenBSD]: https://man.openbsd.org/sendmsg.2 | |
483 | /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendmsg§ion=2 | |
484 | /// [illumos]: https://illumos.org/man/3SOCKET/sendmsg | |
485 | #[inline] | |
486 | pub fn sendmsg_v4( | |
487 | socket: impl AsFd, | |
488 | addr: &SocketAddrV4, | |
489 | iov: &[IoSlice<'_>], | |
490 | control: &mut SendAncillaryBuffer<'_, '_, '_>, | |
491 | flags: SendFlags, | |
492 | ) -> io::Result<usize> { | |
493 | backend::net::syscalls::sendmsg_v4(socket.as_fd(), addr, iov, control, flags) | |
494 | } | |
495 | ||
496 | /// `sendmsg(msghdr)`—Sends a message on a socket to a specific IPv6 address. | |
497 | /// | |
498 | /// # References | |
499 | /// - [POSIX] | |
500 | /// - [Linux] | |
501 | /// - [Apple] | |
502 | /// - [FreeBSD] | |
503 | /// - [NetBSD] | |
504 | /// - [OpenBSD] | |
505 | /// - [DragonFly BSD] | |
506 | /// - [illumos] | |
507 | /// | |
508 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendmsg.html | |
509 | /// [Linux]: https://man7.org/linux/man-pages/man2/sendmsg.2.html | |
510 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendmsg.2.html | |
511 | /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendmsg&sektion=2 | |
512 | /// [NetBSD]: https://man.netbsd.org/sendmsg.2 | |
513 | /// [OpenBSD]: https://man.openbsd.org/sendmsg.2 | |
514 | /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendmsg§ion=2 | |
515 | /// [illumos]: https://illumos.org/man/3SOCKET/sendmsg | |
516 | #[inline] | |
517 | pub fn sendmsg_v6( | |
518 | socket: impl AsFd, | |
519 | addr: &SocketAddrV6, | |
520 | iov: &[IoSlice<'_>], | |
521 | control: &mut SendAncillaryBuffer<'_, '_, '_>, | |
522 | flags: SendFlags, | |
523 | ) -> io::Result<usize> { | |
524 | backend::net::syscalls::sendmsg_v6(socket.as_fd(), addr, iov, control, flags) | |
525 | } | |
526 | ||
527 | /// `sendmsg(msghdr)`—Sends a message on a socket to a specific Unix-domain | |
528 | /// address. | |
529 | /// | |
530 | /// # References | |
531 | /// - [POSIX] | |
532 | /// - [Linux] | |
533 | /// - [Apple] | |
534 | /// - [FreeBSD] | |
535 | /// - [NetBSD] | |
536 | /// - [OpenBSD] | |
537 | /// - [DragonFly BSD] | |
538 | /// - [illumos] | |
539 | /// | |
540 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendmsg.html | |
541 | /// [Linux]: https://man7.org/linux/man-pages/man2/sendmsg.2.html | |
542 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendmsg.2.html | |
543 | /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendmsg&sektion=2 | |
544 | /// [NetBSD]: https://man.netbsd.org/sendmsg.2 | |
545 | /// [OpenBSD]: https://man.openbsd.org/sendmsg.2 | |
546 | /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendmsg§ion=2 | |
547 | /// [illumos]: https://illumos.org/man/3SOCKET/sendmsg | |
548 | #[inline] | |
549 | #[cfg(unix)] | |
550 | pub fn sendmsg_unix( | |
551 | socket: impl AsFd, | |
552 | addr: &super::SocketAddrUnix, | |
553 | iov: &[IoSlice<'_>], | |
554 | control: &mut SendAncillaryBuffer<'_, '_, '_>, | |
555 | flags: SendFlags, | |
556 | ) -> io::Result<usize> { | |
557 | backend::net::syscalls::sendmsg_unix(socket.as_fd(), addr, iov, control, flags) | |
558 | } | |
559 | ||
560 | /// `sendmsg(msghdr)`—Sends a message on a socket to a specific address. | |
561 | /// | |
562 | /// # References | |
563 | /// - [POSIX] | |
564 | /// - [Linux] | |
565 | /// - [Apple] | |
566 | /// - [FreeBSD] | |
567 | /// - [NetBSD] | |
568 | /// - [OpenBSD] | |
569 | /// - [DragonFly BSD] | |
570 | /// - [illumos] | |
571 | /// | |
572 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendmsg.html | |
573 | /// [Linux]: https://man7.org/linux/man-pages/man2/sendmsg.2.html | |
574 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sendmsg.2.html | |
575 | /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=sendmsg&sektion=2 | |
576 | /// [NetBSD]: https://man.netbsd.org/sendmsg.2 | |
577 | /// [OpenBSD]: https://man.openbsd.org/sendmsg.2 | |
578 | /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=sendmsg§ion=2 | |
579 | /// [illumos]: https://illumos.org/man/3SOCKET/sendmsg | |
580 | #[inline] | |
581 | pub fn sendmsg_any( | |
582 | socket: impl AsFd, | |
583 | addr: Option<&SocketAddrAny>, | |
584 | iov: &[IoSlice<'_>], | |
585 | control: &mut SendAncillaryBuffer<'_, '_, '_>, | |
586 | flags: SendFlags, | |
587 | ) -> io::Result<usize> { | |
588 | match addr { | |
589 | None => backend::net::syscalls::sendmsg(socket.as_fd(), iov, control, flags), | |
590 | Some(SocketAddrAny::V4(addr)) => { | |
591 | backend::net::syscalls::sendmsg_v4(socket.as_fd(), addr, iov, control, flags) | |
592 | } | |
593 | Some(SocketAddrAny::V6(addr)) => { | |
594 | backend::net::syscalls::sendmsg_v6(socket.as_fd(), addr, iov, control, flags) | |
595 | } | |
596 | #[cfg(unix)] | |
597 | Some(SocketAddrAny::Unix(addr)) => { | |
598 | backend::net::syscalls::sendmsg_unix(socket.as_fd(), addr, iov, control, flags) | |
599 | } | |
600 | } | |
601 | } | |
602 | ||
603 | /// `recvmsg(msghdr)`—Receives a message from a socket. | |
604 | /// | |
605 | /// # References | |
606 | /// - [POSIX] | |
607 | /// - [Linux] | |
608 | /// - [Apple] | |
609 | /// - [FreeBSD] | |
610 | /// - [NetBSD] | |
611 | /// - [OpenBSD] | |
612 | /// - [DragonFly BSD] | |
613 | /// - [illumos] | |
614 | /// | |
615 | /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html | |
616 | /// [Linux]: https://man7.org/linux/man-pages/man2/recvmsg.2.html | |
617 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/recvmsg.2.html | |
618 | /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=recvmsg&sektion=2 | |
619 | /// [NetBSD]: https://man.netbsd.org/recvmsg.2 | |
620 | /// [OpenBSD]: https://man.openbsd.org/recvmsg.2 | |
621 | /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=recvmsg§ion=2 | |
622 | /// [illumos]: https://illumos.org/man/3SOCKET/recvmsg | |
623 | #[inline] | |
624 | pub fn recvmsg( | |
625 | socket: impl AsFd, | |
626 | iov: &mut [IoSliceMut<'_>], | |
627 | control: &mut RecvAncillaryBuffer<'_>, | |
628 | flags: RecvFlags, | |
629 | ) -> io::Result<RecvMsgReturn> { | |
630 | backend::net::syscalls::recvmsg(socket.as_fd(), iov, control, flags) | |
631 | } | |
632 | ||
633 | /// The result of a successful [`recvmsg`] call. | |
634 | pub struct RecvMsgReturn { | |
635 | /// The number of bytes received. | |
636 | pub bytes: usize, | |
637 | ||
638 | /// The flags received. | |
639 | pub flags: RecvFlags, | |
640 | ||
641 | /// The address of the socket we received from, if any. | |
642 | pub address: Option<SocketAddrAny>, | |
643 | } | |
644 | ||
645 | /// An iterator over data in an ancillary buffer. | |
646 | pub struct AncillaryIter<'data, T> { | |
647 | /// The data we're iterating over. | |
648 | data: &'data mut [u8], | |
649 | ||
650 | /// The raw data we're removing. | |
651 | _marker: PhantomData<T>, | |
652 | } | |
653 | ||
654 | impl<'data, T> AncillaryIter<'data, T> { | |
655 | /// Create a new iterator over data in an ancillary buffer. | |
656 | /// | |
657 | /// # Safety | |
658 | /// | |
659 | /// The buffer must contain valid ancillary data. | |
660 | unsafe fn new(data: &'data mut [u8]) -> Self { | |
661 | assert_eq!(data.len() % size_of::<T>(), 0); | |
662 | ||
663 | Self { | |
664 | data, | |
665 | _marker: PhantomData, | |
666 | } | |
667 | } | |
668 | } | |
669 | ||
670 | impl<'data, T> Drop for AncillaryIter<'data, T> { | |
671 | fn drop(&mut self) { | |
672 | self.for_each(drop); | |
673 | } | |
674 | } | |
675 | ||
676 | impl<T> Iterator for AncillaryIter<'_, T> { | |
677 | type Item = T; | |
678 | ||
679 | fn next(&mut self) -> Option<Self::Item> { | |
680 | // See if there is a next item. | |
681 | if self.data.len() < size_of::<T>() { | |
682 | return None; | |
683 | } | |
684 | ||
685 | // Get the next item. | |
686 | let item = unsafe { self.data.as_ptr().cast::<T>().read_unaligned() }; | |
687 | ||
688 | // Move forward. | |
689 | let data = take(&mut self.data); | |
690 | self.data = &mut data[size_of::<T>()..]; | |
691 | ||
692 | Some(item) | |
693 | } | |
694 | ||
695 | fn size_hint(&self) -> (usize, Option<usize>) { | |
696 | let len = self.len(); | |
697 | (len, Some(len)) | |
698 | } | |
699 | ||
700 | fn count(self) -> usize { | |
701 | self.len() | |
702 | } | |
703 | ||
704 | fn last(mut self) -> Option<Self::Item> { | |
705 | self.next_back() | |
706 | } | |
707 | } | |
708 | ||
709 | impl<T> FusedIterator for AncillaryIter<'_, T> {} | |
710 | ||
711 | impl<T> ExactSizeIterator for AncillaryIter<'_, T> { | |
712 | fn len(&self) -> usize { | |
713 | self.data.len() / size_of::<T>() | |
714 | } | |
715 | } | |
716 | ||
717 | impl<T> DoubleEndedIterator for AncillaryIter<'_, T> { | |
718 | fn next_back(&mut self) -> Option<Self::Item> { | |
719 | // See if there is a next item. | |
720 | if self.data.len() < size_of::<T>() { | |
721 | return None; | |
722 | } | |
723 | ||
724 | // Get the next item. | |
725 | let item = unsafe { | |
726 | let ptr = self.data.as_ptr().add(self.data.len() - size_of::<T>()); | |
727 | ptr.cast::<T>().read_unaligned() | |
728 | }; | |
729 | ||
730 | // Move forward. | |
731 | let len = self.data.len(); | |
732 | let data = take(&mut self.data); | |
733 | self.data = &mut data[..len - size_of::<T>()]; | |
734 | ||
735 | Some(item) | |
736 | } | |
737 | } | |
738 | ||
739 | mod messages { | |
740 | use crate::backend::c; | |
781aab86 | 741 | use crate::backend::net::msghdr; |
fe692bf9 FG |
742 | use core::iter::FusedIterator; |
743 | use core::marker::PhantomData; | |
fe692bf9 FG |
744 | use core::ptr::NonNull; |
745 | ||
746 | /// An iterator over the messages in an ancillary buffer. | |
747 | pub(super) struct Messages<'buf> { | |
ed00b5ec | 748 | /// The message header we're using to iterate over the messages. |
fe692bf9 FG |
749 | msghdr: c::msghdr, |
750 | ||
751 | /// The current pointer to the next message header to return. | |
752 | /// | |
753 | /// This has a lifetime of `'buf`. | |
754 | header: Option<NonNull<c::cmsghdr>>, | |
755 | ||
756 | /// Capture the original lifetime of the buffer. | |
757 | _buffer: PhantomData<&'buf mut [u8]>, | |
758 | } | |
759 | ||
760 | impl<'buf> Messages<'buf> { | |
761 | /// Create a new iterator over messages from a byte buffer. | |
762 | pub(super) fn new(buf: &'buf mut [u8]) -> Self { | |
763 | let msghdr = { | |
781aab86 | 764 | let mut h = msghdr::zero_msghdr(); |
fe692bf9 FG |
765 | h.msg_control = buf.as_mut_ptr().cast(); |
766 | h.msg_controllen = buf.len().try_into().expect("buffer too large for msghdr"); | |
767 | h | |
768 | }; | |
769 | ||
770 | // Get the first header. | |
771 | let header = NonNull::new(unsafe { c::CMSG_FIRSTHDR(&msghdr) }); | |
772 | ||
773 | Self { | |
774 | msghdr, | |
775 | header, | |
776 | _buffer: PhantomData, | |
777 | } | |
778 | } | |
779 | } | |
780 | ||
781 | impl<'a> Iterator for Messages<'a> { | |
782 | type Item = &'a mut c::cmsghdr; | |
783 | ||
784 | #[inline] | |
785 | fn next(&mut self) -> Option<Self::Item> { | |
786 | // Get the current header. | |
787 | let header = self.header?; | |
788 | ||
789 | // Get the next header. | |
790 | self.header = NonNull::new(unsafe { c::CMSG_NXTHDR(&self.msghdr, header.as_ptr()) }); | |
791 | ||
792 | // If the headers are equal, we're done. | |
793 | if Some(header) == self.header { | |
794 | self.header = None; | |
795 | } | |
796 | ||
797 | // SAFETY: The lifetime of `header` is tied to this. | |
798 | Some(unsafe { &mut *header.as_ptr() }) | |
799 | } | |
800 | ||
801 | fn size_hint(&self) -> (usize, Option<usize>) { | |
802 | if self.header.is_some() { | |
803 | // The remaining buffer *could* be filled with zero-length | |
804 | // messages. | |
805 | let max_size = unsafe { c::CMSG_LEN(0) } as usize; | |
806 | let remaining_count = self.msghdr.msg_controllen as usize / max_size; | |
807 | (1, Some(remaining_count)) | |
808 | } else { | |
809 | (0, Some(0)) | |
810 | } | |
811 | } | |
812 | } | |
813 | ||
814 | impl FusedIterator for Messages<'_> {} | |
815 | } |