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