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(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 
451 impl TcpKeepalive {
452     /// Returns a new, empty set of TCP keepalive parameters.
new() -> TcpKeepalive453     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.
with_time(self, time: Duration) -> Self489     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     )]
with_interval(self, interval: Duration) -> Self534     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     )]
with_retries(self, retries: u32) -> Self580     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"))]
593 pub 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"))]
600 impl<'addr, 'bufs, 'control> MsgHdr<'addr, 'bufs, 'control> {
601     /// Create a new `MsgHdr` with all empty/zero fields.
602     #[allow(clippy::new_without_default)]
new() -> MsgHdr<'addr, 'bufs, 'control>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.
with_addr(mut self, addr: &'addr SockAddr) -> Self615     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.
with_buffers(mut self, bufs: &'bufs [IoSlice<'_>]) -> Self624     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.
with_control(mut self, buf: &'control [u8]) -> Self634     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.
with_flags(mut self, flags: sys::c_int) -> Self643     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"))]
650 impl<'name, 'bufs, 'control> fmt::Debug for MsgHdr<'name, 'bufs, 'control> {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result651     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"))]
661 pub 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"))]
672 impl<'addr, 'bufs, 'control> MsgHdrMut<'addr, 'bufs, 'control> {
673     /// Create a new `MsgHdrMut` with all empty/zero fields.
674     #[allow(clippy::new_without_default)]
new() -> MsgHdrMut<'addr, 'bufs, 'control>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)]
with_addr(mut self, addr: &'addr mut SockAddr) -> Self688     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.
with_buffers(mut self, bufs: &'bufs mut [MaybeUninitSlice<'_>]) -> Self697     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.
with_control(mut self, buf: &'control mut [MaybeUninit<u8>]) -> Self706     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.
flags(&self) -> RecvFlags712     pub fn flags(&self) -> RecvFlags {
713         sys::msghdr_flags(&self.inner)
714     }
715 }
716 
717 #[cfg(not(target_os = "redox"))]
718 impl<'name, 'bufs, 'control> fmt::Debug for MsgHdrMut<'name, 'bufs, 'control> {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result719     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
720         "MsgHdrMut".fmt(fmt)
721     }
722 }
723