socket2/
lib.rs

1// Copyright 2015 The Rust Project Developers.
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9//! Utilities for creating and using sockets.
10//!
11//! The goal of this crate is to create and use a socket using advanced
12//! configuration options (those that are not available in the types in the
13//! standard library) without using any unsafe code.
14//!
15//! This crate provides as direct as possible access to the system's
16//! functionality for sockets, this means little effort to provide
17//! cross-platform utilities. It is up to the user to know how to use sockets
18//! when using this crate. *If you don't know how to create a socket using
19//! libc/system calls then this crate is not for you*. Most, if not all,
20//! functions directly relate to the equivalent system call with no error
21//! handling applied, so no handling errors such as [`EINTR`]. As a result using
22//! this crate can be a little wordy, but it should give you maximal flexibility
23//! over configuration of sockets.
24//!
25//! [`EINTR`]: std::io::ErrorKind::Interrupted
26//!
27//! # Examples
28//!
29//! ```no_run
30//! # fn main() -> std::io::Result<()> {
31//! use std::net::{SocketAddr, TcpListener};
32//! use socket2::{Socket, Domain, Type};
33//!
34//! // Create a TCP listener bound to two addresses.
35//! let socket = Socket::new(Domain::IPV6, Type::STREAM, None)?;
36//!
37//! socket.set_only_v6(false)?;
38//! let address: SocketAddr = "[::1]:12345".parse().unwrap();
39//! socket.bind(&address.into())?;
40//! socket.listen(128)?;
41//!
42//! let listener: TcpListener = socket.into();
43//! // ...
44//! # drop(listener);
45//! # Ok(()) }
46//! ```
47//!
48//! ## Features
49//!
50//! This crate has a single feature `all`, which enables all functions even ones
51//! that are not available on all OSs.
52
53#![deny(missing_docs, missing_debug_implementations, rust_2018_idioms)]
54// Show required OS/features on docs.rs.
55#![cfg_attr(docsrs, feature(doc_cfg))]
56// Disallow warnings when running tests.
57#![cfg_attr(test, deny(warnings))]
58// Disallow warnings in examples.
59#![doc(test(attr(deny(warnings))))]
60
61use std::fmt;
62#[cfg(not(target_os = "redox"))]
63use std::io::IoSlice;
64#[cfg(not(target_os = "redox"))]
65use std::marker::PhantomData;
66#[cfg(not(target_os = "redox"))]
67use std::mem;
68use std::mem::MaybeUninit;
69use std::net::SocketAddr;
70use std::ops::{Deref, DerefMut};
71use std::time::Duration;
72
73/// Macro to implement `fmt::Debug` for a type, printing the constant names
74/// rather than a number.
75///
76/// Note this is used in the `sys` module and thus must be defined before
77/// defining the modules.
78macro_rules! impl_debug {
79    (
80        // Type name for which to implement `fmt::Debug`.
81        $type: path,
82        $(
83            $(#[$target: meta])*
84            // The flag(s) to check.
85            // Need to specific the libc crate because Windows doesn't use
86            // `libc` but `windows_sys`.
87            $libc: ident :: $flag: ident
88        ),+ $(,)*
89    ) => {
90        impl std::fmt::Debug for $type {
91            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
92                let string = match self.0 {
93                    $(
94                        $(#[$target])*
95                        $libc :: $flag => stringify!($flag),
96                    )+
97                    n => return write!(f, "{n}"),
98                };
99                f.write_str(string)
100            }
101        }
102    };
103}
104
105/// Macro to convert from one network type to another.
106macro_rules! from {
107    ($from: ty, $for: ty) => {
108        impl From<$from> for $for {
109            fn from(socket: $from) -> $for {
110                #[cfg(unix)]
111                unsafe {
112                    <$for>::from_raw_fd(socket.into_raw_fd())
113                }
114                #[cfg(windows)]
115                unsafe {
116                    <$for>::from_raw_socket(socket.into_raw_socket())
117                }
118            }
119        }
120    };
121}
122
123/// Link to online documentation for (almost) all supported OSs.
124#[rustfmt::skip]
125macro_rules! man_links {
126    // Links to all OSs.
127    ($syscall: tt ( $section: tt ) ) => {
128        concat!(
129            man_links!(__ intro),
130            man_links!(__ unix $syscall($section)),
131            man_links!(__ windows $syscall($section)),
132        )
133    };
134    // Links to Unix-like OSs.
135    (unix: $syscall: tt ( $section: tt ) ) => {
136        concat!(
137            man_links!(__ intro),
138            man_links!(__ unix $syscall($section)),
139        )
140    };
141    // Links to Windows only.
142    (windows: $syscall: tt ( $section: tt ) ) => {
143        concat!(
144            man_links!(__ intro),
145            man_links!(__ windows $syscall($section)),
146        )
147    };
148    // Internals.
149    (__ intro) => {
150        "\n\nAdditional documentation can be found in manual of the OS:\n\n"
151    };
152    // List for Unix-like OSs.
153    (__ unix $syscall: tt ( $section: tt ) ) => {
154        concat!(
155            " * DragonFly BSD: <https://man.dragonflybsd.org/?command=", stringify!($syscall), "&section=", stringify!($section), ">\n",
156            " * FreeBSD: <https://www.freebsd.org/cgi/man.cgi?query=", stringify!($syscall), "&sektion=", stringify!($section), ">\n",
157            " * Linux: <https://man7.org/linux/man-pages/man", stringify!($section), "/", stringify!($syscall), ".", stringify!($section), ".html>\n",
158            " * macOS: <https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/", stringify!($syscall), ".", stringify!($section), ".html> (archived, actually for iOS)\n",
159            " * NetBSD: <https://man.netbsd.org/", stringify!($syscall), ".", stringify!($section), ">\n",
160            " * OpenBSD: <https://man.openbsd.org/", stringify!($syscall), ".", stringify!($section), ">\n",
161            " * iOS: <https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/", stringify!($syscall), ".", stringify!($section), ".html> (archived)\n",
162            " * illumos: <https://illumos.org/man/3SOCKET/", stringify!($syscall), ">\n",
163        )
164    };
165    // List for Window (so just Windows).
166    (__ windows $syscall: tt ( $section: tt ) ) => {
167        concat!(
168            " * Windows: <https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-", stringify!($syscall), ">\n",
169        )
170    };
171}
172
173mod sockaddr;
174mod socket;
175mod sockref;
176
177#[cfg_attr(unix, path = "sys/unix.rs")]
178#[cfg_attr(windows, path = "sys/windows.rs")]
179mod sys;
180
181#[cfg(not(any(windows, unix)))]
182compile_error!("Socket2 doesn't support the compile target");
183
184use sys::c_int;
185
186pub use sockaddr::SockAddr;
187pub use socket::Socket;
188pub use sockref::SockRef;
189
190#[cfg(not(any(
191    target_os = "haiku",
192    target_os = "illumos",
193    target_os = "netbsd",
194    target_os = "redox",
195    target_os = "solaris",
196)))]
197pub use socket::InterfaceIndexOrAddress;
198
199/// Specification of the communication domain for a socket.
200///
201/// This is a newtype wrapper around an integer which provides a nicer API in
202/// addition to an injection point for documentation. Convenience constants such
203/// as [`Domain::IPV4`], [`Domain::IPV6`], etc, are provided to avoid reaching
204/// into libc for various constants.
205///
206/// This type is freely interconvertible with C's `int` type, however, if a raw
207/// value needs to be provided.
208#[derive(Copy, Clone, Eq, PartialEq)]
209pub struct Domain(c_int);
210
211impl Domain {
212    /// Domain for IPv4 communication, corresponding to `AF_INET`.
213    pub const IPV4: Domain = Domain(sys::AF_INET);
214
215    /// Domain for IPv6 communication, corresponding to `AF_INET6`.
216    pub const IPV6: Domain = Domain(sys::AF_INET6);
217
218    /// Domain for Unix socket communication, corresponding to `AF_UNIX`.
219    pub const UNIX: Domain = Domain(sys::AF_UNIX);
220
221    /// Returns the correct domain for `address`.
222    pub const fn for_address(address: SocketAddr) -> Domain {
223        match address {
224            SocketAddr::V4(_) => Domain::IPV4,
225            SocketAddr::V6(_) => Domain::IPV6,
226        }
227    }
228}
229
230impl From<c_int> for Domain {
231    fn from(d: c_int) -> Domain {
232        Domain(d)
233    }
234}
235
236impl From<Domain> for c_int {
237    fn from(d: Domain) -> c_int {
238        d.0
239    }
240}
241
242/// Specification of communication semantics on a socket.
243///
244/// This is a newtype wrapper around an integer which provides a nicer API in
245/// addition to an injection point for documentation. Convenience constants such
246/// as [`Type::STREAM`], [`Type::DGRAM`], etc, are provided to avoid reaching
247/// into libc for various constants.
248///
249/// This type is freely interconvertible with C's `int` type, however, if a raw
250/// value needs to be provided.
251#[derive(Copy, Clone, Eq, PartialEq)]
252pub struct Type(c_int);
253
254impl Type {
255    /// Type corresponding to `SOCK_STREAM`.
256    ///
257    /// Used for protocols such as TCP.
258    pub const STREAM: Type = Type(sys::SOCK_STREAM);
259
260    /// Type corresponding to `SOCK_DGRAM`.
261    ///
262    /// Used for protocols such as UDP.
263    pub const DGRAM: Type = Type(sys::SOCK_DGRAM);
264
265    /// Type corresponding to `SOCK_DCCP`.
266    ///
267    /// Used for the DCCP protocol.
268    #[cfg(all(feature = "all", target_os = "linux"))]
269    #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
270    pub const DCCP: Type = Type(sys::SOCK_DCCP);
271
272    /// Type corresponding to `SOCK_SEQPACKET`.
273    #[cfg(all(feature = "all", not(target_os = "espidf")))]
274    #[cfg_attr(docsrs, doc(cfg(all(feature = "all", not(target_os = "espidf")))))]
275    pub const SEQPACKET: Type = Type(sys::SOCK_SEQPACKET);
276
277    /// Type corresponding to `SOCK_RAW`.
278    #[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))]
279    #[cfg_attr(
280        docsrs,
281        doc(cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf")))))
282    )]
283    pub const RAW: Type = Type(sys::SOCK_RAW);
284}
285
286impl From<c_int> for Type {
287    fn from(t: c_int) -> Type {
288        Type(t)
289    }
290}
291
292impl From<Type> for c_int {
293    fn from(t: Type) -> c_int {
294        t.0
295    }
296}
297
298/// Protocol specification used for creating sockets via `Socket::new`.
299///
300/// This is a newtype wrapper around an integer which provides a nicer API in
301/// addition to an injection point for documentation.
302///
303/// This type is freely interconvertible with C's `int` type, however, if a raw
304/// value needs to be provided.
305#[derive(Copy, Clone, Eq, PartialEq)]
306pub struct Protocol(c_int);
307
308impl Protocol {
309    /// Protocol corresponding to `ICMPv4`.
310    pub const ICMPV4: Protocol = Protocol(sys::IPPROTO_ICMP);
311
312    /// Protocol corresponding to `ICMPv6`.
313    pub const ICMPV6: Protocol = Protocol(sys::IPPROTO_ICMPV6);
314
315    /// Protocol corresponding to `TCP`.
316    pub const TCP: Protocol = Protocol(sys::IPPROTO_TCP);
317
318    /// Protocol corresponding to `UDP`.
319    pub const UDP: Protocol = Protocol(sys::IPPROTO_UDP);
320
321    #[cfg(target_os = "linux")]
322    /// Protocol corresponding to `MPTCP`.
323    pub const MPTCP: Protocol = Protocol(sys::IPPROTO_MPTCP);
324
325    /// Protocol corresponding to `DCCP`.
326    #[cfg(all(feature = "all", target_os = "linux"))]
327    #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
328    pub const DCCP: Protocol = Protocol(sys::IPPROTO_DCCP);
329
330    /// Protocol corresponding to `SCTP`.
331    #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
332    pub const SCTP: Protocol = Protocol(sys::IPPROTO_SCTP);
333
334    /// Protocol corresponding to `UDPLITE`.
335    #[cfg(all(
336        feature = "all",
337        any(
338            target_os = "android",
339            target_os = "freebsd",
340            target_os = "fuchsia",
341            target_os = "linux",
342        )
343    ))]
344    pub const UDPLITE: Protocol = Protocol(sys::IPPROTO_UDPLITE);
345
346    /// Protocol corresponding to `DIVERT`.
347    #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "openbsd")))]
348    pub const DIVERT: Protocol = Protocol(sys::IPPROTO_DIVERT);
349}
350
351impl From<c_int> for Protocol {
352    fn from(p: c_int) -> Protocol {
353        Protocol(p)
354    }
355}
356
357impl From<Protocol> for c_int {
358    fn from(p: Protocol) -> c_int {
359        p.0
360    }
361}
362
363/// Flags for incoming messages.
364///
365/// Flags provide additional information about incoming messages.
366#[cfg(not(target_os = "redox"))]
367#[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))]
368#[derive(Copy, Clone, Eq, PartialEq)]
369pub struct RecvFlags(c_int);
370
371#[cfg(not(target_os = "redox"))]
372impl RecvFlags {
373    /// Check if the message contains a truncated datagram.
374    ///
375    /// This flag is only used for datagram-based sockets,
376    /// not for stream sockets.
377    ///
378    /// On Unix this corresponds to the `MSG_TRUNC` flag.
379    /// On Windows this corresponds to the `WSAEMSGSIZE` error code.
380    #[cfg(not(target_os = "espidf"))]
381    pub const fn is_truncated(self) -> bool {
382        self.0 & sys::MSG_TRUNC != 0
383    }
384}
385
386/// A version of [`IoSliceMut`] that allows the buffer to be uninitialised.
387///
388/// [`IoSliceMut`]: std::io::IoSliceMut
389#[repr(transparent)]
390pub struct MaybeUninitSlice<'a>(sys::MaybeUninitSlice<'a>);
391
392impl<'a> fmt::Debug for MaybeUninitSlice<'a> {
393    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
394        fmt::Debug::fmt(self.0.as_slice(), fmt)
395    }
396}
397
398impl<'a> MaybeUninitSlice<'a> {
399    /// Creates a new `MaybeUninitSlice` wrapping a byte slice.
400    ///
401    /// # Panics
402    ///
403    /// Panics on Windows if the slice is larger than 4GB.
404    pub fn new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a> {
405        MaybeUninitSlice(sys::MaybeUninitSlice::new(buf))
406    }
407}
408
409impl<'a> Deref for MaybeUninitSlice<'a> {
410    type Target = [MaybeUninit<u8>];
411
412    fn deref(&self) -> &[MaybeUninit<u8>] {
413        self.0.as_slice()
414    }
415}
416
417impl<'a> DerefMut for MaybeUninitSlice<'a> {
418    fn deref_mut(&mut self) -> &mut [MaybeUninit<u8>] {
419        self.0.as_mut_slice()
420    }
421}
422
423/// Configures a socket's TCP keepalive parameters.
424///
425/// See [`Socket::set_tcp_keepalive`].
426#[derive(Debug, Clone)]
427pub struct TcpKeepalive {
428    #[cfg_attr(any(target_os = "openbsd", target_os = "vita"), allow(dead_code))]
429    time: Option<Duration>,
430    #[cfg(not(any(
431        target_os = "openbsd",
432        target_os = "redox",
433        target_os = "solaris",
434        target_os = "nto",
435        target_os = "espidf",
436        target_os = "vita",
437    )))]
438    interval: Option<Duration>,
439    #[cfg(not(any(
440        target_os = "openbsd",
441        target_os = "redox",
442        target_os = "solaris",
443        target_os = "windows",
444        target_os = "nto",
445        target_os = "espidf",
446        target_os = "vita",
447    )))]
448    retries: Option<u32>,
449}
450
451impl TcpKeepalive {
452    /// Returns a new, empty set of TCP keepalive parameters.
453    pub const fn new() -> TcpKeepalive {
454        TcpKeepalive {
455            time: None,
456            #[cfg(not(any(
457                target_os = "openbsd",
458                target_os = "redox",
459                target_os = "solaris",
460                target_os = "nto",
461                target_os = "espidf",
462                target_os = "vita",
463            )))]
464            interval: None,
465            #[cfg(not(any(
466                target_os = "openbsd",
467                target_os = "redox",
468                target_os = "solaris",
469                target_os = "windows",
470                target_os = "nto",
471                target_os = "espidf",
472                target_os = "vita",
473            )))]
474            retries: None,
475        }
476    }
477
478    /// Set the amount of time after which TCP keepalive probes will be sent on
479    /// idle connections.
480    ///
481    /// This will set `TCP_KEEPALIVE` on macOS and iOS, and
482    /// `TCP_KEEPIDLE` on all other Unix operating systems, except
483    /// OpenBSD and Haiku which don't support any way to set this
484    /// option. On Windows, this sets the value of the `tcp_keepalive`
485    /// struct's `keepalivetime` field.
486    ///
487    /// Some platforms specify this value in seconds, so sub-second
488    /// specifications may be omitted.
489    pub const fn with_time(self, time: Duration) -> Self {
490        Self {
491            time: Some(time),
492            ..self
493        }
494    }
495
496    /// Set the value of the `TCP_KEEPINTVL` option. On Windows, this sets the
497    /// value of the `tcp_keepalive` struct's `keepaliveinterval` field.
498    ///
499    /// Sets the time interval between TCP keepalive probes.
500    ///
501    /// Some platforms specify this value in seconds, so sub-second
502    /// specifications may be omitted.
503    #[cfg(any(
504        target_os = "android",
505        target_os = "dragonfly",
506        target_os = "freebsd",
507        target_os = "fuchsia",
508        target_os = "illumos",
509        target_os = "ios",
510        target_os = "linux",
511        target_os = "macos",
512        target_os = "netbsd",
513        target_os = "tvos",
514        target_os = "watchos",
515        target_os = "windows",
516    ))]
517    #[cfg_attr(
518        docsrs,
519        doc(cfg(any(
520            target_os = "android",
521            target_os = "dragonfly",
522            target_os = "freebsd",
523            target_os = "fuchsia",
524            target_os = "illumos",
525            target_os = "ios",
526            target_os = "linux",
527            target_os = "macos",
528            target_os = "netbsd",
529            target_os = "tvos",
530            target_os = "watchos",
531            target_os = "windows",
532        )))
533    )]
534    pub const fn with_interval(self, interval: Duration) -> Self {
535        Self {
536            interval: Some(interval),
537            ..self
538        }
539    }
540
541    /// Set the value of the `TCP_KEEPCNT` option.
542    ///
543    /// Set the maximum number of TCP keepalive probes that will be sent before
544    /// dropping a connection, if TCP keepalive is enabled on this socket.
545    #[cfg(all(
546        feature = "all",
547        any(
548            target_os = "android",
549            target_os = "dragonfly",
550            target_os = "freebsd",
551            target_os = "fuchsia",
552            target_os = "illumos",
553            target_os = "ios",
554            target_os = "linux",
555            target_os = "macos",
556            target_os = "netbsd",
557            target_os = "tvos",
558            target_os = "watchos",
559        )
560    ))]
561    #[cfg_attr(
562        docsrs,
563        doc(cfg(all(
564            feature = "all",
565            any(
566                target_os = "android",
567                target_os = "dragonfly",
568                target_os = "freebsd",
569                target_os = "fuchsia",
570                target_os = "illumos",
571                target_os = "ios",
572                target_os = "linux",
573                target_os = "macos",
574                target_os = "netbsd",
575                target_os = "tvos",
576                target_os = "watchos",
577            )
578        )))
579    )]
580    pub const fn with_retries(self, retries: u32) -> Self {
581        Self {
582            retries: Some(retries),
583            ..self
584        }
585    }
586}
587
588/// Configuration of a `sendmsg(2)` system call.
589///
590/// This wraps `msghdr` on Unix and `WSAMSG` on Windows. Also see [`MsgHdrMut`]
591/// for the variant used by `recvmsg(2)`.
592#[cfg(not(target_os = "redox"))]
593pub struct MsgHdr<'addr, 'bufs, 'control> {
594    inner: sys::msghdr,
595    #[allow(clippy::type_complexity)]
596    _lifetimes: PhantomData<(&'addr SockAddr, &'bufs IoSlice<'bufs>, &'control [u8])>,
597}
598
599#[cfg(not(target_os = "redox"))]
600impl<'addr, 'bufs, 'control> MsgHdr<'addr, 'bufs, 'control> {
601    /// Create a new `MsgHdr` with all empty/zero fields.
602    #[allow(clippy::new_without_default)]
603    pub fn new() -> MsgHdr<'addr, 'bufs, 'control> {
604        // SAFETY: all zero is valid for `msghdr` and `WSAMSG`.
605        MsgHdr {
606            inner: unsafe { mem::zeroed() },
607            _lifetimes: PhantomData,
608        }
609    }
610
611    /// Set the address (name) of the message.
612    ///
613    /// Corresponds to setting `msg_name` and `msg_namelen` on Unix and `name`
614    /// and `namelen` on Windows.
615    pub fn with_addr(mut self, addr: &'addr SockAddr) -> Self {
616        sys::set_msghdr_name(&mut self.inner, addr);
617        self
618    }
619
620    /// Set the buffer(s) of the message.
621    ///
622    /// Corresponds to setting `msg_iov` and `msg_iovlen` on Unix and `lpBuffers`
623    /// and `dwBufferCount` on Windows.
624    pub fn with_buffers(mut self, bufs: &'bufs [IoSlice<'_>]) -> Self {
625        let ptr = bufs.as_ptr() as *mut _;
626        sys::set_msghdr_iov(&mut self.inner, ptr, bufs.len());
627        self
628    }
629
630    /// Set the control buffer of the message.
631    ///
632    /// Corresponds to setting `msg_control` and `msg_controllen` on Unix and
633    /// `Control` on Windows.
634    pub fn with_control(mut self, buf: &'control [u8]) -> Self {
635        let ptr = buf.as_ptr() as *mut _;
636        sys::set_msghdr_control(&mut self.inner, ptr, buf.len());
637        self
638    }
639
640    /// Set the flags of the message.
641    ///
642    /// Corresponds to setting `msg_flags` on Unix and `dwFlags` on Windows.
643    pub fn with_flags(mut self, flags: sys::c_int) -> Self {
644        sys::set_msghdr_flags(&mut self.inner, flags);
645        self
646    }
647}
648
649#[cfg(not(target_os = "redox"))]
650impl<'name, 'bufs, 'control> fmt::Debug for MsgHdr<'name, 'bufs, 'control> {
651    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
652        "MsgHdr".fmt(fmt)
653    }
654}
655
656/// Configuration of a `recvmsg(2)` system call.
657///
658/// This wraps `msghdr` on Unix and `WSAMSG` on Windows. Also see [`MsgHdr`] for
659/// the variant used by `sendmsg(2)`.
660#[cfg(not(target_os = "redox"))]
661pub struct MsgHdrMut<'addr, 'bufs, 'control> {
662    inner: sys::msghdr,
663    #[allow(clippy::type_complexity)]
664    _lifetimes: PhantomData<(
665        &'addr mut SockAddr,
666        &'bufs mut MaybeUninitSlice<'bufs>,
667        &'control mut [u8],
668    )>,
669}
670
671#[cfg(not(target_os = "redox"))]
672impl<'addr, 'bufs, 'control> MsgHdrMut<'addr, 'bufs, 'control> {
673    /// Create a new `MsgHdrMut` with all empty/zero fields.
674    #[allow(clippy::new_without_default)]
675    pub fn new() -> MsgHdrMut<'addr, 'bufs, 'control> {
676        // SAFETY: all zero is valid for `msghdr` and `WSAMSG`.
677        MsgHdrMut {
678            inner: unsafe { mem::zeroed() },
679            _lifetimes: PhantomData,
680        }
681    }
682
683    /// Set the mutable address (name) of the message.
684    ///
685    /// Corresponds to setting `msg_name` and `msg_namelen` on Unix and `name`
686    /// and `namelen` on Windows.
687    #[allow(clippy::needless_pass_by_ref_mut)]
688    pub fn with_addr(mut self, addr: &'addr mut SockAddr) -> Self {
689        sys::set_msghdr_name(&mut self.inner, addr);
690        self
691    }
692
693    /// Set the mutable buffer(s) of the message.
694    ///
695    /// Corresponds to setting `msg_iov` and `msg_iovlen` on Unix and `lpBuffers`
696    /// and `dwBufferCount` on Windows.
697    pub fn with_buffers(mut self, bufs: &'bufs mut [MaybeUninitSlice<'_>]) -> Self {
698        sys::set_msghdr_iov(&mut self.inner, bufs.as_mut_ptr().cast(), bufs.len());
699        self
700    }
701
702    /// Set the mutable control buffer of the message.
703    ///
704    /// Corresponds to setting `msg_control` and `msg_controllen` on Unix and
705    /// `Control` on Windows.
706    pub fn with_control(mut self, buf: &'control mut [MaybeUninit<u8>]) -> Self {
707        sys::set_msghdr_control(&mut self.inner, buf.as_mut_ptr().cast(), buf.len());
708        self
709    }
710
711    /// Returns the flags of the message.
712    pub fn flags(&self) -> RecvFlags {
713        sys::msghdr_flags(&self.inner)
714    }
715}
716
717#[cfg(not(target_os = "redox"))]
718impl<'name, 'bufs, 'control> fmt::Debug for MsgHdrMut<'name, 'bufs, 'control> {
719    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
720        "MsgHdrMut".fmt(fmt)
721    }
722}