Coverage Report

Created: 2025-05-07 06:59

/rust/registry/src/index.crates.io-6f17d22bba15001f/socket2-0.5.9/src/lib.rs
Line
Count
Source (jump to first uncovered line)
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
0
            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
92
0
                let string = match self.0 {
93
                    $(
94
                        $(#[$target])*
95
0
                        $libc :: $flag => stringify!($flag),
96
                    )+
97
0
                    n => return write!(f, "{n}"),
98
                };
99
0
                f.write_str(string)
100
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
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
0
            fn from(socket: $from) -> $for {
110
0
                #[cfg(unix)]
111
0
                unsafe {
112
0
                    <$for>::from_raw_fd(socket.into_raw_fd())
113
0
                }
114
0
                #[cfg(windows)]
115
0
                unsafe {
116
0
                    <$for>::from_raw_socket(socket.into_raw_socket())
117
0
                }
118
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: <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::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::net::udp::UdpSocket as core::convert::From<socket2::socket::Socket>>::from
Unexecuted instantiation: <std::os::unix::net::datagram::UnixDatagram as core::convert::From<socket2::socket::Socket>>::from
Unexecuted instantiation: <std::os::unix::net::stream::UnixStream as core::convert::From<socket2::socket::Socket>>::from
Unexecuted instantiation: <std::os::unix::net::listener::UnixListener as core::convert::From<socket2::socket::Socket>>::from
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`.
222
0
    pub const fn for_address(address: SocketAddr) -> Domain {
223
0
        match address {
224
0
            SocketAddr::V4(_) => Domain::IPV4,
225
0
            SocketAddr::V6(_) => Domain::IPV6,
226
        }
227
0
    }
228
}
229
230
impl From<c_int> for Domain {
231
0
    fn from(d: c_int) -> Domain {
232
0
        Domain(d)
233
0
    }
234
}
235
236
impl From<Domain> for c_int {
237
0
    fn from(d: Domain) -> c_int {
238
0
        d.0
239
0
    }
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 {
287
0
    fn from(t: c_int) -> Type {
288
0
        Type(t)
289
0
    }
290
}
291
292
impl From<Type> for c_int {
293
0
    fn from(t: Type) -> c_int {
294
0
        t.0
295
0
    }
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 {
352
0
    fn from(p: c_int) -> Protocol {
353
0
        Protocol(p)
354
0
    }
355
}
356
357
impl From<Protocol> for c_int {
358
0
    fn from(p: Protocol) -> c_int {
359
0
        p.0
360
0
    }
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"))]
381
0
    pub const fn is_truncated(self) -> bool {
382
0
        self.0 & sys::MSG_TRUNC != 0
383
0
    }
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> {
393
0
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
394
0
        fmt::Debug::fmt(self.0.as_slice(), fmt)
395
0
    }
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.
404
0
    pub fn new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a> {
405
0
        MaybeUninitSlice(sys::MaybeUninitSlice::new(buf))
406
0
    }
407
}
408
409
impl<'a> Deref for MaybeUninitSlice<'a> {
410
    type Target = [MaybeUninit<u8>];
411
412
0
    fn deref(&self) -> &[MaybeUninit<u8>] {
413
0
        self.0.as_slice()
414
0
    }
415
}
416
417
impl<'a> DerefMut for MaybeUninitSlice<'a> {
418
0
    fn deref_mut(&mut self) -> &mut [MaybeUninit<u8>] {
419
0
        self.0.as_mut_slice()
420
0
    }
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)]
459
0
    pub const fn new() -> TcpKeepalive {
460
0
        TcpKeepalive {
461
0
            time: None,
462
0
            #[cfg(not(any(
463
0
                target_os = "openbsd",
464
0
                target_os = "redox",
465
0
                target_os = "solaris",
466
0
                target_os = "nto",
467
0
                target_os = "espidf",
468
0
                target_os = "vita",
469
0
                target_os = "haiku",
470
0
            )))]
471
0
            interval: None,
472
0
            #[cfg(not(any(
473
0
                target_os = "openbsd",
474
0
                target_os = "redox",
475
0
                target_os = "solaris",
476
0
                target_os = "windows",
477
0
                target_os = "nto",
478
0
                target_os = "espidf",
479
0
                target_os = "vita",
480
0
                target_os = "haiku",
481
0
            )))]
482
0
            retries: None,
483
0
        }
484
0
    }
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.
497
0
    pub const fn with_time(self, time: Duration) -> Self {
498
0
        Self {
499
0
            time: Some(time),
500
0
            ..self
501
0
        }
502
0
    }
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
    )]
544
0
    pub const fn with_interval(self, interval: Duration) -> Self {
545
0
        Self {
546
0
            interval: Some(interval),
547
0
            ..self
548
0
        }
549
0
    }
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
    )]
592
0
    pub const fn with_retries(self, retries: u32) -> Self {
593
0
        Self {
594
0
            retries: Some(retries),
595
0
            ..self
596
0
        }
597
0
    }
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)]
615
0
    pub fn new() -> MsgHdr<'addr, 'bufs, 'control> {
616
0
        // SAFETY: all zero is valid for `msghdr` and `WSAMSG`.
617
0
        MsgHdr {
618
0
            inner: unsafe { mem::zeroed() },
619
0
            _lifetimes: PhantomData,
620
0
        }
621
0
    }
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.
627
0
    pub fn with_addr(mut self, addr: &'addr SockAddr) -> Self {
628
0
        sys::set_msghdr_name(&mut self.inner, addr);
629
0
        self
630
0
    }
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.
636
0
    pub fn with_buffers(mut self, bufs: &'bufs [IoSlice<'_>]) -> Self {
637
0
        let ptr = bufs.as_ptr() as *mut _;
638
0
        sys::set_msghdr_iov(&mut self.inner, ptr, bufs.len());
639
0
        self
640
0
    }
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.
646
0
    pub fn with_control(mut self, buf: &'control [u8]) -> Self {
647
0
        let ptr = buf.as_ptr() as *mut _;
648
0
        sys::set_msghdr_control(&mut self.inner, ptr, buf.len());
649
0
        self
650
0
    }
651
652
    /// Set the flags of the message.
653
    ///
654
    /// Corresponds to setting `msg_flags` on Unix and `dwFlags` on Windows.
655
0
    pub fn with_flags(mut self, flags: sys::c_int) -> Self {
656
0
        sys::set_msghdr_flags(&mut self.inner, flags);
657
0
        self
658
0
    }
659
}
660
661
#[cfg(not(target_os = "redox"))]
662
impl<'name, 'bufs, 'control> fmt::Debug for MsgHdr<'name, 'bufs, 'control> {
663
0
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
664
0
        "MsgHdr".fmt(fmt)
665
0
    }
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)]
687
0
    pub fn new() -> MsgHdrMut<'addr, 'bufs, 'control> {
688
0
        // SAFETY: all zero is valid for `msghdr` and `WSAMSG`.
689
0
        MsgHdrMut {
690
0
            inner: unsafe { mem::zeroed() },
691
0
            _lifetimes: PhantomData,
692
0
        }
693
0
    }
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)]
700
0
    pub fn with_addr(mut self, addr: &'addr mut SockAddr) -> Self {
701
0
        sys::set_msghdr_name(&mut self.inner, addr);
702
0
        self
703
0
    }
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.
709
0
    pub fn with_buffers(mut self, bufs: &'bufs mut [MaybeUninitSlice<'_>]) -> Self {
710
0
        sys::set_msghdr_iov(&mut self.inner, bufs.as_mut_ptr().cast(), bufs.len());
711
0
        self
712
0
    }
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.
718
0
    pub fn with_control(mut self, buf: &'control mut [MaybeUninit<u8>]) -> Self {
719
0
        sys::set_msghdr_control(&mut self.inner, buf.as_mut_ptr().cast(), buf.len());
720
0
        self
721
0
    }
722
723
    /// Returns the flags of the message.
724
0
    pub fn flags(&self) -> RecvFlags {
725
0
        sys::msghdr_flags(&self.inner)
726
0
    }
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.
733
0
    pub fn control_len(&self) -> usize {
734
0
        sys::msghdr_control_len(&self.inner)
735
0
    }
736
}
737
738
#[cfg(not(target_os = "redox"))]
739
impl<'name, 'bufs, 'control> fmt::Debug for MsgHdrMut<'name, 'bufs, 'control> {
740
0
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
741
0
        "MsgHdrMut".fmt(fmt)
742
0
    }
743
}