Coverage Report

Created: 2026-09-14 06:40

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