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