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