• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
61 use std::fmt;
62 #[cfg(not(target_os = "redox"))]
63 use std::io::IoSlice;
64 #[cfg(not(target_os = "redox"))]
65 use std::marker::PhantomData;
66 #[cfg(not(target_os = "redox"))]
67 use std::mem;
68 use std::mem::MaybeUninit;
69 use std::net::SocketAddr;
70 use std::ops::{Deref, DerefMut};
71 use 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.
78 macro_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.
106 macro_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]
125 macro_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 
173 mod sockaddr;
174 mod socket;
175 mod sockref;
176 
177 #[cfg_attr(unix, path = "sys/unix.rs")]
178 #[cfg_attr(windows, path = "sys/windows.rs")]
179 mod sys;
180 
181 #[cfg(not(any(windows, unix)))]
182 compile_error!("Socket2 doesn't support the compile target");
183 
184 use sys::c_int;
185 
186 pub use sockaddr::SockAddr;
187 pub use socket::Socket;
188 pub 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 )))]
197 pub 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)]
209 pub struct Domain(c_int);
210 
211 impl 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`.
for_address(address: SocketAddr) -> Domain222     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 
230 impl From<c_int> for Domain {
from(d: c_int) -> Domain231     fn from(d: c_int) -> Domain {
232         Domain(d)
233     }
234 }
235 
236 impl From<Domain> for c_int {
from(d: Domain) -> c_int237     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)]
252 pub struct Type(c_int);
253 
254 impl 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 
286 impl From<c_int> for Type {
from(t: c_int) -> Type287     fn from(t: c_int) -> Type {
288         Type(t)
289     }
290 }
291 
292 impl From<Type> for c_int {
from(t: Type) -> c_int293     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)]
306 pub struct Protocol(c_int);
307 
308 impl 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 
351 impl From<c_int> for Protocol {
from(p: c_int) -> Protocol352     fn from(p: c_int) -> Protocol {
353         Protocol(p)
354     }
355 }
356 
357 impl From<Protocol> for c_int {
from(p: Protocol) -> c_int358     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)]
369 pub struct RecvFlags(c_int);
370 
371 #[cfg(not(target_os = "redox"))]
372 impl 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"))]
is_truncated(self) -> bool381     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)]
390 pub struct MaybeUninitSlice<'a>(sys::MaybeUninitSlice<'a>);
391 
392 impl<'a> fmt::Debug for MaybeUninitSlice<'a> {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result393     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
394         fmt::Debug::fmt(self.0.as_slice(), fmt)
395     }
396 }
397 
398 impl<'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.
new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a>404     pub fn new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a> {
405         MaybeUninitSlice(sys::MaybeUninitSlice::new(buf))
406     }
407 }
408 
409 impl<'a> Deref for MaybeUninitSlice<'a> {
410     type Target = [MaybeUninit<u8>];
411 
deref(&self) -> &[MaybeUninit<u8>]412     fn deref(&self) -> &[MaybeUninit<u8>] {
413         self.0.as_slice()
414     }
415 }
416 
417 impl<'a> DerefMut for MaybeUninitSlice<'a> {
deref_mut(&mut self) -> &mut [MaybeUninit<u8>]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)]
427 pub struct TcpKeepalive {
428     #[cfg_attr(
429         any(target_os = "openbsd", target_os = "haiku", target_os = "vita"),
430         allow(dead_code)
431     )]
432     time: Option<Duration>,
433     #[cfg(not(any(
434         target_os = "openbsd",
435         target_os = "redox",
436         target_os = "solaris",
437         target_os = "nto",
438         target_os = "espidf",
439         target_os = "vita",
440         target_os = "haiku",
441     )))]
442     interval: Option<Duration>,
443     #[cfg(not(any(
444         target_os = "openbsd",
445         target_os = "redox",
446         target_os = "solaris",
447         target_os = "windows",
448         target_os = "nto",
449         target_os = "espidf",
450         target_os = "vita",
451         target_os = "haiku",
452     )))]
453     retries: Option<u32>,
454 }
455 
456 impl TcpKeepalive {
457     /// Returns a new, empty set of TCP keepalive parameters.
458     #[allow(clippy::new_without_default)]
new() -> TcpKeepalive459     pub const fn new() -> TcpKeepalive {
460         TcpKeepalive {
461             time: None,
462             #[cfg(not(any(
463                 target_os = "openbsd",
464                 target_os = "redox",
465                 target_os = "solaris",
466                 target_os = "nto",
467                 target_os = "espidf",
468                 target_os = "vita",
469                 target_os = "haiku",
470             )))]
471             interval: None,
472             #[cfg(not(any(
473                 target_os = "openbsd",
474                 target_os = "redox",
475                 target_os = "solaris",
476                 target_os = "windows",
477                 target_os = "nto",
478                 target_os = "espidf",
479                 target_os = "vita",
480                 target_os = "haiku",
481             )))]
482             retries: None,
483         }
484     }
485 
486     /// Set the amount of time after which TCP keepalive probes will be sent on
487     /// idle connections.
488     ///
489     /// This will set `TCP_KEEPALIVE` on macOS and iOS, and
490     /// `TCP_KEEPIDLE` on all other Unix operating systems, except
491     /// OpenBSD and Haiku which don't support any way to set this
492     /// option. On Windows, this sets the value of the `tcp_keepalive`
493     /// struct's `keepalivetime` field.
494     ///
495     /// Some platforms specify this value in seconds, so sub-second
496     /// specifications may be omitted.
with_time(self, time: Duration) -> Self497     pub const fn with_time(self, time: Duration) -> Self {
498         Self {
499             time: Some(time),
500             ..self
501         }
502     }
503 
504     /// Set the value of the `TCP_KEEPINTVL` option. On Windows, this sets the
505     /// value of the `tcp_keepalive` struct's `keepaliveinterval` field.
506     ///
507     /// Sets the time interval between TCP keepalive probes.
508     ///
509     /// Some platforms specify this value in seconds, so sub-second
510     /// specifications may be omitted.
511     #[cfg(any(
512         target_os = "android",
513         target_os = "dragonfly",
514         target_os = "freebsd",
515         target_os = "fuchsia",
516         target_os = "illumos",
517         target_os = "ios",
518         target_os = "visionos",
519         target_os = "linux",
520         target_os = "macos",
521         target_os = "netbsd",
522         target_os = "tvos",
523         target_os = "watchos",
524         target_os = "windows",
525     ))]
526     #[cfg_attr(
527         docsrs,
528         doc(cfg(any(
529             target_os = "android",
530             target_os = "dragonfly",
531             target_os = "freebsd",
532             target_os = "fuchsia",
533             target_os = "illumos",
534             target_os = "ios",
535             target_os = "visionos",
536             target_os = "linux",
537             target_os = "macos",
538             target_os = "netbsd",
539             target_os = "tvos",
540             target_os = "watchos",
541             target_os = "windows",
542         )))
543     )]
with_interval(self, interval: Duration) -> Self544     pub const fn with_interval(self, interval: Duration) -> Self {
545         Self {
546             interval: Some(interval),
547             ..self
548         }
549     }
550 
551     /// Set the value of the `TCP_KEEPCNT` option.
552     ///
553     /// Set the maximum number of TCP keepalive probes that will be sent before
554     /// dropping a connection, if TCP keepalive is enabled on this socket.
555     #[cfg(all(
556         feature = "all",
557         any(
558             target_os = "android",
559             target_os = "dragonfly",
560             target_os = "freebsd",
561             target_os = "fuchsia",
562             target_os = "illumos",
563             target_os = "ios",
564             target_os = "visionos",
565             target_os = "linux",
566             target_os = "macos",
567             target_os = "netbsd",
568             target_os = "tvos",
569             target_os = "watchos",
570         )
571     ))]
572     #[cfg_attr(
573         docsrs,
574         doc(cfg(all(
575             feature = "all",
576             any(
577                 target_os = "android",
578                 target_os = "dragonfly",
579                 target_os = "freebsd",
580                 target_os = "fuchsia",
581                 target_os = "illumos",
582                 target_os = "ios",
583                 target_os = "visionos",
584                 target_os = "linux",
585                 target_os = "macos",
586                 target_os = "netbsd",
587                 target_os = "tvos",
588                 target_os = "watchos",
589             )
590         )))
591     )]
with_retries(self, retries: u32) -> Self592     pub const fn with_retries(self, retries: u32) -> Self {
593         Self {
594             retries: Some(retries),
595             ..self
596         }
597     }
598 }
599 
600 /// Configuration of a `sendmsg(2)` system call.
601 ///
602 /// This wraps `msghdr` on Unix and `WSAMSG` on Windows. Also see [`MsgHdrMut`]
603 /// for the variant used by `recvmsg(2)`.
604 #[cfg(not(target_os = "redox"))]
605 pub struct MsgHdr<'addr, 'bufs, 'control> {
606     inner: sys::msghdr,
607     #[allow(clippy::type_complexity)]
608     _lifetimes: PhantomData<(&'addr SockAddr, &'bufs IoSlice<'bufs>, &'control [u8])>,
609 }
610 
611 #[cfg(not(target_os = "redox"))]
612 impl<'addr, 'bufs, 'control> MsgHdr<'addr, 'bufs, 'control> {
613     /// Create a new `MsgHdr` with all empty/zero fields.
614     #[allow(clippy::new_without_default)]
new() -> MsgHdr<'addr, 'bufs, 'control>615     pub fn new() -> MsgHdr<'addr, 'bufs, 'control> {
616         // SAFETY: all zero is valid for `msghdr` and `WSAMSG`.
617         MsgHdr {
618             inner: unsafe { mem::zeroed() },
619             _lifetimes: PhantomData,
620         }
621     }
622 
623     /// Set the address (name) of the message.
624     ///
625     /// Corresponds to setting `msg_name` and `msg_namelen` on Unix and `name`
626     /// and `namelen` on Windows.
with_addr(mut self, addr: &'addr SockAddr) -> Self627     pub fn with_addr(mut self, addr: &'addr SockAddr) -> Self {
628         sys::set_msghdr_name(&mut self.inner, addr);
629         self
630     }
631 
632     /// Set the buffer(s) of the message.
633     ///
634     /// Corresponds to setting `msg_iov` and `msg_iovlen` on Unix and `lpBuffers`
635     /// and `dwBufferCount` on Windows.
with_buffers(mut self, bufs: &'bufs [IoSlice<'_>]) -> Self636     pub fn with_buffers(mut self, bufs: &'bufs [IoSlice<'_>]) -> Self {
637         let ptr = bufs.as_ptr() as *mut _;
638         sys::set_msghdr_iov(&mut self.inner, ptr, bufs.len());
639         self
640     }
641 
642     /// Set the control buffer of the message.
643     ///
644     /// Corresponds to setting `msg_control` and `msg_controllen` on Unix and
645     /// `Control` on Windows.
with_control(mut self, buf: &'control [u8]) -> Self646     pub fn with_control(mut self, buf: &'control [u8]) -> Self {
647         let ptr = buf.as_ptr() as *mut _;
648         sys::set_msghdr_control(&mut self.inner, ptr, buf.len());
649         self
650     }
651 
652     /// Set the flags of the message.
653     ///
654     /// Corresponds to setting `msg_flags` on Unix and `dwFlags` on Windows.
with_flags(mut self, flags: sys::c_int) -> Self655     pub fn with_flags(mut self, flags: sys::c_int) -> Self {
656         sys::set_msghdr_flags(&mut self.inner, flags);
657         self
658     }
659 }
660 
661 #[cfg(not(target_os = "redox"))]
662 impl<'name, 'bufs, 'control> fmt::Debug for MsgHdr<'name, 'bufs, 'control> {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result663     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
664         "MsgHdr".fmt(fmt)
665     }
666 }
667 
668 /// Configuration of a `recvmsg(2)` system call.
669 ///
670 /// This wraps `msghdr` on Unix and `WSAMSG` on Windows. Also see [`MsgHdr`] for
671 /// the variant used by `sendmsg(2)`.
672 #[cfg(not(target_os = "redox"))]
673 pub struct MsgHdrMut<'addr, 'bufs, 'control> {
674     inner: sys::msghdr,
675     #[allow(clippy::type_complexity)]
676     _lifetimes: PhantomData<(
677         &'addr mut SockAddr,
678         &'bufs mut MaybeUninitSlice<'bufs>,
679         &'control mut [u8],
680     )>,
681 }
682 
683 #[cfg(not(target_os = "redox"))]
684 impl<'addr, 'bufs, 'control> MsgHdrMut<'addr, 'bufs, 'control> {
685     /// Create a new `MsgHdrMut` with all empty/zero fields.
686     #[allow(clippy::new_without_default)]
new() -> MsgHdrMut<'addr, 'bufs, 'control>687     pub fn new() -> MsgHdrMut<'addr, 'bufs, 'control> {
688         // SAFETY: all zero is valid for `msghdr` and `WSAMSG`.
689         MsgHdrMut {
690             inner: unsafe { mem::zeroed() },
691             _lifetimes: PhantomData,
692         }
693     }
694 
695     /// Set the mutable address (name) of the message.
696     ///
697     /// Corresponds to setting `msg_name` and `msg_namelen` on Unix and `name`
698     /// and `namelen` on Windows.
699     #[allow(clippy::needless_pass_by_ref_mut)]
with_addr(mut self, addr: &'addr mut SockAddr) -> Self700     pub fn with_addr(mut self, addr: &'addr mut SockAddr) -> Self {
701         sys::set_msghdr_name(&mut self.inner, addr);
702         self
703     }
704 
705     /// Set the mutable buffer(s) of the message.
706     ///
707     /// Corresponds to setting `msg_iov` and `msg_iovlen` on Unix and `lpBuffers`
708     /// and `dwBufferCount` on Windows.
with_buffers(mut self, bufs: &'bufs mut [MaybeUninitSlice<'_>]) -> Self709     pub fn with_buffers(mut self, bufs: &'bufs mut [MaybeUninitSlice<'_>]) -> Self {
710         sys::set_msghdr_iov(&mut self.inner, bufs.as_mut_ptr().cast(), bufs.len());
711         self
712     }
713 
714     /// Set the mutable control buffer of the message.
715     ///
716     /// Corresponds to setting `msg_control` and `msg_controllen` on Unix and
717     /// `Control` on Windows.
with_control(mut self, buf: &'control mut [MaybeUninit<u8>]) -> Self718     pub fn with_control(mut self, buf: &'control mut [MaybeUninit<u8>]) -> Self {
719         sys::set_msghdr_control(&mut self.inner, buf.as_mut_ptr().cast(), buf.len());
720         self
721     }
722 
723     /// Returns the flags of the message.
flags(&self) -> RecvFlags724     pub fn flags(&self) -> RecvFlags {
725         sys::msghdr_flags(&self.inner)
726     }
727 
728     /// Gets the length of the control buffer.
729     ///
730     /// Can be used to determine how much, if any, of the control buffer was filled by `recvmsg`.
731     ///
732     /// Corresponds to `msg_controllen` on Unix and `Control.len` on Windows.
control_len(&self) -> usize733     pub fn control_len(&self) -> usize {
734         sys::msghdr_control_len(&self.inner)
735     }
736 }
737 
738 #[cfg(not(target_os = "redox"))]
739 impl<'name, 'bufs, 'control> fmt::Debug for MsgHdrMut<'name, 'bufs, 'control> {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result740     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
741         "MsgHdrMut".fmt(fmt)
742     }
743 }
744