Coverage Report

Created: 2026-03-31 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/socket2-0.6.3/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")))]
65
use std::io::IoSlice;
66
#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
67
use std::marker::PhantomData;
68
#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
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(feature = "all", not(any(target_os = "espidf", target_os = "wasi"))))]
283
    pub const SEQPACKET: Type = Type(sys::SOCK_SEQPACKET);
284
285
    /// Type corresponding to `SOCK_RAW`.
286
    #[cfg(all(
287
        feature = "all",
288
        not(any(target_os = "redox", target_os = "espidf", target_os = "wasi"))
289
    ))]
290
    pub const RAW: Type = Type(sys::SOCK_RAW);
291
}
292
293
impl From<c_int> for Type {
294
0
    fn from(t: c_int) -> Type {
295
0
        Type(t)
296
0
    }
297
}
298
299
impl From<Type> for c_int {
300
0
    fn from(t: Type) -> c_int {
301
0
        t.0
302
0
    }
303
}
304
305
/// Protocol specification used for creating sockets via `Socket::new`.
306
///
307
/// This is a newtype wrapper around an integer which provides a nicer API in
308
/// addition to an injection point for documentation.
309
///
310
/// This type is freely interconvertible with C's `int` type, however, if a raw
311
/// value needs to be provided.
312
#[derive(Copy, Clone, Eq, PartialEq)]
313
pub struct Protocol(c_int);
314
315
impl Protocol {
316
    /// Protocol corresponding to `ICMPv4`.
317
    #[cfg(not(target_os = "wasi"))]
318
    pub const ICMPV4: Protocol = Protocol(sys::IPPROTO_ICMP);
319
320
    /// Protocol corresponding to `ICMPv6`.
321
    #[cfg(not(target_os = "wasi"))]
322
    pub const ICMPV6: Protocol = Protocol(sys::IPPROTO_ICMPV6);
323
324
    /// Protocol corresponding to `TCP`.
325
    pub const TCP: Protocol = Protocol(sys::IPPROTO_TCP);
326
327
    /// Protocol corresponding to `UDP`.
328
    pub const UDP: Protocol = Protocol(sys::IPPROTO_UDP);
329
330
    #[cfg(target_os = "linux")]
331
    /// Protocol corresponding to `MPTCP`.
332
    pub const MPTCP: Protocol = Protocol(sys::IPPROTO_MPTCP);
333
334
    /// Protocol corresponding to `DCCP`.
335
    #[cfg(all(feature = "all", target_os = "linux"))]
336
    pub const DCCP: Protocol = Protocol(sys::IPPROTO_DCCP);
337
338
    /// Protocol corresponding to `SCTP`.
339
    #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
340
    pub const SCTP: Protocol = Protocol(sys::IPPROTO_SCTP);
341
342
    /// Protocol corresponding to `UDPLITE`.
343
    #[cfg(all(
344
        feature = "all",
345
        any(
346
            target_os = "android",
347
            target_os = "freebsd",
348
            target_os = "fuchsia",
349
            target_os = "linux",
350
        )
351
    ))]
352
    pub const UDPLITE: Protocol = Protocol(sys::IPPROTO_UDPLITE);
353
354
    /// Protocol corresponding to `DIVERT`.
355
    #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "openbsd")))]
356
    pub const DIVERT: Protocol = Protocol(sys::IPPROTO_DIVERT);
357
}
358
359
impl From<c_int> for Protocol {
360
0
    fn from(p: c_int) -> Protocol {
361
0
        Protocol(p)
362
0
    }
363
}
364
365
impl From<Protocol> for c_int {
366
0
    fn from(p: Protocol) -> c_int {
367
0
        p.0
368
0
    }
369
}
370
371
/// Flags for incoming messages.
372
///
373
/// Flags provide additional information about incoming messages.
374
#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
375
#[derive(Copy, Clone, Eq, PartialEq)]
376
pub struct RecvFlags(c_int);
377
378
#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
379
impl RecvFlags {
380
    /// Check if the message contains a truncated datagram.
381
    ///
382
    /// This flag is only used for datagram-based sockets,
383
    /// not for stream sockets.
384
    ///
385
    /// On Unix this corresponds to the `MSG_TRUNC` flag.
386
    /// On Windows this corresponds to the `WSAEMSGSIZE` error code.
387
    #[cfg(not(target_os = "espidf"))]
388
0
    pub const fn is_truncated(self) -> bool {
389
0
        self.0 & sys::MSG_TRUNC != 0
390
0
    }
391
}
392
393
/// A version of [`IoSliceMut`] that allows the buffer to be uninitialised.
394
///
395
/// [`IoSliceMut`]: std::io::IoSliceMut
396
#[repr(transparent)]
397
pub struct MaybeUninitSlice<'a>(sys::MaybeUninitSlice<'a>);
398
399
impl<'a> fmt::Debug for MaybeUninitSlice<'a> {
400
0
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
401
0
        fmt::Debug::fmt(self.0.as_slice(), fmt)
402
0
    }
403
}
404
405
impl<'a> MaybeUninitSlice<'a> {
406
    /// Creates a new `MaybeUninitSlice` wrapping a byte slice.
407
    ///
408
    /// # Panics
409
    ///
410
    /// Panics on Windows if the slice is larger than 4GB.
411
0
    pub fn new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a> {
412
0
        MaybeUninitSlice(sys::MaybeUninitSlice::new(buf))
413
0
    }
414
}
415
416
impl<'a> Deref for MaybeUninitSlice<'a> {
417
    type Target = [MaybeUninit<u8>];
418
419
0
    fn deref(&self) -> &[MaybeUninit<u8>] {
420
0
        self.0.as_slice()
421
0
    }
422
}
423
424
impl<'a> DerefMut for MaybeUninitSlice<'a> {
425
0
    fn deref_mut(&mut self) -> &mut [MaybeUninit<u8>] {
426
0
        self.0.as_mut_slice()
427
0
    }
428
}
429
430
/// Configures a socket's TCP keepalive parameters.
431
///
432
/// See [`Socket::set_tcp_keepalive`].
433
#[derive(Debug, Clone)]
434
pub struct TcpKeepalive {
435
    #[cfg_attr(
436
        any(target_os = "openbsd", target_os = "haiku", target_os = "vita"),
437
        allow(dead_code)
438
    )]
439
    time: Option<Duration>,
440
    #[cfg(not(any(
441
        target_os = "openbsd",
442
        target_os = "redox",
443
        target_os = "solaris",
444
        target_os = "nto",
445
        target_os = "espidf",
446
        target_os = "vita",
447
        target_os = "haiku",
448
    )))]
449
    interval: Option<Duration>,
450
    #[cfg(not(any(
451
        target_os = "openbsd",
452
        target_os = "redox",
453
        target_os = "solaris",
454
        target_os = "nto",
455
        target_os = "espidf",
456
        target_os = "vita",
457
        target_os = "haiku",
458
    )))]
459
    retries: Option<u32>,
460
}
461
462
impl TcpKeepalive {
463
    /// Returns a new, empty set of TCP keepalive parameters.
464
    #[allow(clippy::new_without_default)]
465
0
    pub const fn new() -> TcpKeepalive {
466
0
        TcpKeepalive {
467
0
            time: None,
468
0
            #[cfg(not(any(
469
0
                target_os = "openbsd",
470
0
                target_os = "redox",
471
0
                target_os = "solaris",
472
0
                target_os = "nto",
473
0
                target_os = "espidf",
474
0
                target_os = "vita",
475
0
                target_os = "haiku",
476
0
            )))]
477
0
            interval: 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
            )))]
487
0
            retries: None,
488
0
        }
489
0
    }
490
491
    /// Set the amount of time after which TCP keepalive probes will be sent on
492
    /// idle connections.
493
    ///
494
    /// This will set `TCP_KEEPALIVE` on macOS and iOS, and
495
    /// `TCP_KEEPIDLE` on all other Unix operating systems, except
496
    /// OpenBSD and Haiku which don't support any way to set this
497
    /// option. On Windows, this sets the value of the `tcp_keepalive`
498
    /// struct's `keepalivetime` field.
499
    ///
500
    /// Some platforms specify this value in seconds, so sub-second
501
    /// specifications may be omitted.
502
0
    pub const fn with_time(self, time: Duration) -> Self {
503
0
        Self {
504
0
            time: Some(time),
505
0
            ..self
506
0
        }
507
0
    }
508
509
    /// Set the value of the `TCP_KEEPINTVL` option. On Windows, this sets the
510
    /// value of the `tcp_keepalive` struct's `keepaliveinterval` field.
511
    ///
512
    /// Sets the time interval between TCP keepalive probes.
513
    ///
514
    /// Some platforms specify this value in seconds, so sub-second
515
    /// specifications may be omitted.
516
    #[cfg(any(
517
        target_os = "android",
518
        target_os = "dragonfly",
519
        target_os = "freebsd",
520
        target_os = "fuchsia",
521
        target_os = "illumos",
522
        target_os = "ios",
523
        target_os = "visionos",
524
        target_os = "linux",
525
        target_os = "macos",
526
        target_os = "netbsd",
527
        target_os = "tvos",
528
        target_os = "watchos",
529
        target_os = "windows",
530
        target_os = "cygwin",
531
        all(target_os = "wasi", not(target_env = "p1")),
532
    ))]
533
0
    pub const fn with_interval(self, interval: Duration) -> Self {
534
0
        Self {
535
0
            interval: Some(interval),
536
0
            ..self
537
0
        }
538
0
    }
539
540
    /// Set the value of the `TCP_KEEPCNT` option.
541
    ///
542
    /// Set the maximum number of TCP keepalive probes that will be sent before
543
    /// dropping a connection, if TCP keepalive is enabled on this socket.
544
    #[cfg(all(
545
        feature = "all",
546
        any(
547
            target_os = "android",
548
            target_os = "dragonfly",
549
            target_os = "freebsd",
550
            target_os = "fuchsia",
551
            target_os = "illumos",
552
            target_os = "ios",
553
            target_os = "visionos",
554
            target_os = "linux",
555
            target_os = "macos",
556
            target_os = "netbsd",
557
            target_os = "tvos",
558
            target_os = "watchos",
559
            target_os = "cygwin",
560
            target_os = "windows",
561
            all(target_os = "wasi", not(target_env = "p1")),
562
        )
563
    ))]
564
0
    pub const fn with_retries(self, retries: u32) -> Self {
565
0
        Self {
566
0
            retries: Some(retries),
567
0
            ..self
568
0
        }
569
0
    }
570
}
571
572
/// Configuration of a `sendmsg(2)` system call.
573
///
574
/// This wraps `msghdr` on Unix and `WSAMSG` on Windows. Also see [`MsgHdrMut`]
575
/// for the variant used by `recvmsg(2)`.
576
#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
577
#[repr(transparent)]
578
pub struct MsgHdr<'addr, 'bufs, 'control> {
579
    inner: sys::msghdr,
580
    #[allow(clippy::type_complexity)]
581
    _lifetimes: PhantomData<(&'addr SockAddr, &'bufs IoSlice<'bufs>, &'control [u8])>,
582
}
583
584
#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
585
impl<'addr, 'bufs, 'control> MsgHdr<'addr, 'bufs, 'control> {
586
    /// Create a new `MsgHdr` with all empty/zero fields.
587
    #[allow(clippy::new_without_default)]
588
0
    pub fn new() -> MsgHdr<'addr, 'bufs, 'control> {
589
        // SAFETY: all zero is valid for `msghdr` and `WSAMSG`.
590
0
        MsgHdr {
591
0
            inner: unsafe { mem::zeroed() },
592
0
            _lifetimes: PhantomData,
593
0
        }
594
0
    }
595
596
    /// Set the address (name) of the message.
597
    ///
598
    /// Corresponds to setting `msg_name` and `msg_namelen` on Unix and `name`
599
    /// and `namelen` on Windows.
600
0
    pub fn with_addr(mut self, addr: &'addr SockAddr) -> Self {
601
0
        sys::set_msghdr_name(&mut self.inner, addr);
602
0
        self
603
0
    }
604
605
    /// Set the buffer(s) of the message.
606
    ///
607
    /// Corresponds to setting `msg_iov` and `msg_iovlen` on Unix and `lpBuffers`
608
    /// and `dwBufferCount` on Windows.
609
0
    pub fn with_buffers(mut self, bufs: &'bufs [IoSlice<'_>]) -> Self {
610
0
        let ptr = bufs.as_ptr() as *mut _;
611
0
        sys::set_msghdr_iov(&mut self.inner, ptr, bufs.len());
612
0
        self
613
0
    }
614
615
    /// Set the control buffer of the message.
616
    ///
617
    /// Corresponds to setting `msg_control` and `msg_controllen` on Unix and
618
    /// `Control` on Windows.
619
0
    pub fn with_control(mut self, buf: &'control [u8]) -> Self {
620
0
        let ptr = buf.as_ptr() as *mut _;
621
0
        sys::set_msghdr_control(&mut self.inner, ptr, buf.len());
622
0
        self
623
0
    }
624
625
    /// Set the flags of the message.
626
    ///
627
    /// Corresponds to setting `msg_flags` on Unix and `dwFlags` on Windows.
628
0
    pub fn with_flags(mut self, flags: sys::c_int) -> Self {
629
0
        sys::set_msghdr_flags(&mut self.inner, flags);
630
0
        self
631
0
    }
632
}
633
634
#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
635
impl<'name, 'bufs, 'control> fmt::Debug for MsgHdr<'name, 'bufs, 'control> {
636
0
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
637
0
        "MsgHdr".fmt(fmt)
638
0
    }
639
}
640
641
/// Configuration of a `recvmsg(2)` system call.
642
///
643
/// This wraps `msghdr` on Unix and `WSAMSG` on Windows. Also see [`MsgHdr`] for
644
/// the variant used by `sendmsg(2)`.
645
#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
646
#[repr(transparent)]
647
pub struct MsgHdrMut<'addr, 'bufs, 'control> {
648
    inner: sys::msghdr,
649
    #[allow(clippy::type_complexity)]
650
    _lifetimes: PhantomData<(
651
        &'addr mut SockAddr,
652
        &'bufs mut MaybeUninitSlice<'bufs>,
653
        &'control mut [u8],
654
    )>,
655
}
656
657
#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
658
impl<'addr, 'bufs, 'control> MsgHdrMut<'addr, 'bufs, 'control> {
659
    /// Create a new `MsgHdrMut` with all empty/zero fields.
660
    #[allow(clippy::new_without_default)]
661
0
    pub fn new() -> MsgHdrMut<'addr, 'bufs, 'control> {
662
        // SAFETY: all zero is valid for `msghdr` and `WSAMSG`.
663
0
        MsgHdrMut {
664
0
            inner: unsafe { mem::zeroed() },
665
0
            _lifetimes: PhantomData,
666
0
        }
667
0
    }
668
669
    /// Set the mutable address (name) of the message.
670
    ///
671
    /// Corresponds to setting `msg_name` and `msg_namelen` on Unix and `name`
672
    /// and `namelen` on Windows.
673
    #[allow(clippy::needless_pass_by_ref_mut)]
674
0
    pub fn with_addr(mut self, addr: &'addr mut SockAddr) -> Self {
675
0
        sys::set_msghdr_name(&mut self.inner, addr);
676
0
        self
677
0
    }
678
679
    /// Set the mutable buffer(s) of the message.
680
    ///
681
    /// Corresponds to setting `msg_iov` and `msg_iovlen` on Unix and `lpBuffers`
682
    /// and `dwBufferCount` on Windows.
683
0
    pub fn with_buffers(mut self, bufs: &'bufs mut [MaybeUninitSlice<'_>]) -> Self {
684
0
        sys::set_msghdr_iov(&mut self.inner, bufs.as_mut_ptr().cast(), bufs.len());
685
0
        self
686
0
    }
687
688
    /// Set the mutable control buffer of the message.
689
    ///
690
    /// Corresponds to setting `msg_control` and `msg_controllen` on Unix and
691
    /// `Control` on Windows.
692
0
    pub fn with_control(mut self, buf: &'control mut [MaybeUninit<u8>]) -> Self {
693
0
        sys::set_msghdr_control(&mut self.inner, buf.as_mut_ptr().cast(), buf.len());
694
0
        self
695
0
    }
696
697
    /// Returns the flags of the message.
698
0
    pub fn flags(&self) -> RecvFlags {
699
0
        sys::msghdr_flags(&self.inner)
700
0
    }
701
702
    /// Gets the length of the control buffer.
703
    ///
704
    /// Can be used to determine how much, if any, of the control buffer was filled by `recvmsg`.
705
    ///
706
    /// Corresponds to `msg_controllen` on Unix and `Control.len` on Windows.
707
0
    pub fn control_len(&self) -> usize {
708
0
        sys::msghdr_control_len(&self.inner)
709
0
    }
710
}
711
712
#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
713
impl<'name, 'bufs, 'control> fmt::Debug for MsgHdrMut<'name, 'bufs, 'control> {
714
0
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
715
0
        "MsgHdrMut".fmt(fmt)
716
0
    }
717
}