Skip to main content

socket2/
socket.rs

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
9use std::fmt;
10use std::io::{self, Read, Write};
11#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
12use std::io::{IoSlice, IoSliceMut};
13use std::mem::MaybeUninit;
14#[cfg(not(target_os = "nto"))]
15use std::net::Ipv6Addr;
16use std::net::{self, Ipv4Addr, Shutdown};
17#[cfg(any(unix, all(target_os = "wasi", not(target_env = "p1"))))]
18use std::os::fd::{FromRawFd, IntoRawFd};
19#[cfg(windows)]
20use std::os::windows::io::{FromRawSocket, IntoRawSocket};
21use std::time::Duration;
22
23use crate::sys::{self, c_int, getsockopt, setsockopt, Bool};
24#[cfg(all(unix, not(any(target_os = "redox", target_os = "horizon"))))]
25use crate::MsgHdrMut;
26use crate::{Domain, Protocol, SockAddr, TcpKeepalive, Type};
27#[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
28use crate::{MaybeUninitSlice, MsgHdr, RecvFlags};
29
30/// Owned wrapper around a system socket.
31///
32/// This type simply wraps an instance of a file descriptor (`c_int`) on Unix
33/// and an instance of `SOCKET` on Windows. This is the main type exported by
34/// this crate and is intended to mirror the raw semantics of sockets on
35/// platforms as closely as possible. Almost all methods correspond to
36/// precisely one libc or OS API call which is essentially just a "Rustic
37/// translation" of what's below.
38///
39/// ## Converting to and from other types
40///
41/// This type can be freely converted into the network primitives provided by
42/// the standard library, such as [`TcpStream`] or [`UdpSocket`], using the
43/// [`From`] trait, see the example below.
44///
45/// [`TcpStream`]: std::net::TcpStream
46/// [`UdpSocket`]: std::net::UdpSocket
47///
48/// # Notes
49///
50/// Some methods that set options on `Socket` require two system calls to set
51/// their options without overwriting previously set options. We do this by
52/// first getting the current settings, applying the desired changes, and then
53/// updating the settings. This means that the operation is **not** atomic. This
54/// can lead to a data race when two threads are changing options in parallel.
55///
56/// # Examples
57/// ```no_run
58/// # fn main() -> std::io::Result<()> {
59/// use std::net::{SocketAddr, TcpListener};
60/// use socket2::{Socket, Domain, Type};
61///
62/// // create a TCP listener
63/// let socket = Socket::new(Domain::IPV6, Type::STREAM, None)?;
64///
65/// let address: SocketAddr = "[::1]:12345".parse().unwrap();
66/// let address = address.into();
67/// socket.bind(&address)?;
68/// socket.listen(128)?;
69///
70/// let listener: TcpListener = socket.into();
71/// // ...
72/// # drop(listener);
73/// # Ok(()) }
74/// ```
75pub struct Socket {
76    inner: sys::Socket,
77}
78
79impl Socket {
80    /// # Safety
81    ///
82    /// The caller must ensure `raw` is a valid file descriptor/socket. NOTE:
83    /// this should really be marked `unsafe`, but this being an internal
84    /// function, often passed as mapping function, it's makes it very
85    /// inconvenient to mark it as `unsafe`.
86    pub(crate) fn from_raw(raw: sys::RawSocket) -> Socket {
87        Socket {
88            // SAFETY: the caller must ensure that `raw` is a valid file
89            // descriptor, but when it isn't it could return I/O errors, or
90            // potentially close a fd it doesn't own. All of that isn't memory
91            // unsafe, so it's not desired but never memory unsafe or causes UB.
92            inner: unsafe { sys::socket_from_raw(raw) },
93        }
94    }
95
96    pub(crate) fn as_raw(&self) -> sys::RawSocket {
97        sys::socket_as_raw(&self.inner)
98    }
99
100    pub(crate) fn into_raw(self) -> sys::RawSocket {
101        sys::socket_into_raw(self.inner)
102    }
103
104    /// Creates a new socket and sets common flags.
105    ///
106    /// This function corresponds to `socket(2)` on Unix and `WSASocketW` on
107    /// Windows.
108    ///
109    /// On Unix-like systems, the close-on-exec flag is set on the new socket.
110    /// Additionally, on Apple platforms `SOCK_NOSIGPIPE` is set. On Windows,
111    /// the socket is made non-inheritable.
112    ///
113    /// [`Socket::new_raw`] can be used if you don't want these flags to be set.
114    #[doc = man_links!(socket(2))]
115    pub fn new(domain: Domain, ty: Type, protocol: Option<Protocol>) -> io::Result<Socket> {
116        let ty = set_common_type(ty);
117        Socket::new_raw(domain, ty, protocol).and_then(set_common_flags)
118    }
119
120    /// Creates a new socket ready to be configured.
121    ///
122    /// This function corresponds to `socket(2)` on Unix and `WSASocketW` on
123    /// Windows and simply creates a new socket, no other configuration is done.
124    pub fn new_raw(domain: Domain, ty: Type, protocol: Option<Protocol>) -> io::Result<Socket> {
125        let protocol = protocol.map_or(0, |p| p.0);
126        sys::socket(domain.0, ty.0, protocol).map(Socket::from_raw)
127    }
128
129    /// Creates a pair of sockets which are connected to each other.
130    ///
131    /// This function corresponds to `socketpair(2)`.
132    ///
133    /// This function sets the same flags as in done for [`Socket::new`],
134    /// [`Socket::pair_raw`] can be used if you don't want to set those flags.
135    #[doc = man_links!(unix: socketpair(2))]
136    #[cfg(all(feature = "all", unix))]
137    pub fn pair(
138        domain: Domain,
139        ty: Type,
140        protocol: Option<Protocol>,
141    ) -> io::Result<(Socket, Socket)> {
142        let ty = set_common_type(ty);
143        let (a, b) = Socket::pair_raw(domain, ty, protocol)?;
144        let a = set_common_flags(a)?;
145        let b = set_common_flags(b)?;
146        Ok((a, b))
147    }
148
149    /// Creates a pair of sockets which are connected to each other.
150    ///
151    /// This function corresponds to `socketpair(2)`.
152    #[cfg(all(feature = "all", unix))]
153    pub fn pair_raw(
154        domain: Domain,
155        ty: Type,
156        protocol: Option<Protocol>,
157    ) -> io::Result<(Socket, Socket)> {
158        let protocol = protocol.map_or(0, |p| p.0);
159        sys::socketpair(domain.0, ty.0, protocol)
160            .map(|[a, b]| (Socket::from_raw(a), Socket::from_raw(b)))
161    }
162
163    /// Binds this socket to the specified address.
164    ///
165    /// This function directly corresponds to the `bind(2)` function on Windows
166    /// and Unix.
167    #[doc = man_links!(bind(2))]
168    pub fn bind(&self, address: &SockAddr) -> io::Result<()> {
169        sys::bind(self.as_raw(), address)
170    }
171
172    /// Initiate a connection on this socket to the specified address.
173    ///
174    /// This function directly corresponds to the `connect(2)` function on
175    /// Windows and Unix.
176    ///
177    /// An error will be returned if `listen` or `connect` has already been
178    /// called on this builder.
179    #[doc = man_links!(connect(2))]
180    ///
181    /// # Notes
182    ///
183    /// When using a non-blocking connect (by setting the socket into
184    /// non-blocking mode before calling this function), socket option can't be
185    /// set *while connecting*. This will cause errors on Windows. Socket
186    /// options can be safely set before and after connecting the socket.
187    ///
188    /// On Cygwin, a Unix domain socket connect blocks until the server accepts
189    /// it. If the behavior is not expected, try [`Socket::set_no_peercred`]
190    /// (Cygwin only).
191    #[allow(rustdoc::broken_intra_doc_links)] // Socket::set_no_peercred
192    pub fn connect(&self, address: &SockAddr) -> io::Result<()> {
193        sys::connect(self.as_raw(), address)
194    }
195
196    /// Initiate a connection on this socket to the specified address, only
197    /// only waiting for a certain period of time for the connection to be
198    /// established.
199    ///
200    /// Unlike many other methods on `Socket`, this does *not* correspond to a
201    /// single C function. It sets the socket to nonblocking mode, connects via
202    /// connect(2), and then waits for the connection to complete with poll(2)
203    /// on Unix and select on Windows. When the connection is complete, the
204    /// socket is set back to blocking mode. On Unix, this will loop over
205    /// `EINTR` errors.
206    ///
207    /// # Warnings
208    ///
209    /// The non-blocking state of the socket is overridden by this function -
210    /// it will be returned in blocking mode on success, and in an indeterminate
211    /// state on failure.
212    ///
213    /// If the connection request times out, it may still be processing in the
214    /// background - a second call to `connect` or `connect_timeout` may fail.
215    pub fn connect_timeout(&self, addr: &SockAddr, timeout: Duration) -> io::Result<()> {
216        self.set_nonblocking(true)?;
217        let res = self.connect(addr);
218        self.set_nonblocking(false)?;
219
220        match res {
221            Ok(()) => return Ok(()),
222            Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {}
223            #[cfg(any(unix, all(target_os = "wasi", not(target_env = "p1"))))]
224            Err(ref e) if e.raw_os_error() == Some(libc::EINPROGRESS) => {}
225            Err(e) => return Err(e),
226        }
227
228        sys::poll_connect(self, timeout)
229    }
230
231    /// Mark a socket as ready to accept incoming connection requests using
232    /// [`Socket::accept()`].
233    ///
234    /// This function directly corresponds to the `listen(2)` function on
235    /// Windows and Unix.
236    ///
237    /// An error will be returned if `listen` or `connect` has already been
238    /// called on this builder.
239    #[doc = man_links!(listen(2))]
240    pub fn listen(&self, backlog: c_int) -> io::Result<()> {
241        sys::listen(self.as_raw(), backlog)
242    }
243
244    /// Accept a new incoming connection from this listener.
245    ///
246    /// This function uses `accept4(2)` on platforms that support it and
247    /// `accept(2)` platforms that do not.
248    ///
249    /// This function sets the same flags as in done for [`Socket::new`],
250    /// [`Socket::accept_raw`] can be used if you don't want to set those flags.
251    #[doc = man_links!(accept(2))]
252    ///
253    /// # Notes
254    ///
255    /// On Cygwin, a Unix domain socket connect blocks until the server accepts
256    /// it. If the behavior is not expected, try [`Socket::set_no_peercred`]
257    /// (Cygwin only).
258    #[allow(rustdoc::broken_intra_doc_links)] // Socket::set_no_peercred
259    pub fn accept(&self) -> io::Result<(Socket, SockAddr)> {
260        // Use `accept4` on platforms that support it.
261        #[cfg(any(
262            target_os = "android",
263            target_os = "dragonfly",
264            target_os = "freebsd",
265            target_os = "fuchsia",
266            target_os = "illumos",
267            target_os = "linux",
268            target_os = "netbsd",
269            target_os = "openbsd",
270            target_os = "cygwin",
271        ))]
272        return self._accept4(libc::SOCK_CLOEXEC);
273
274        // Fall back to `accept` on platforms that do not support `accept4`.
275        #[cfg(not(any(
276            target_os = "android",
277            target_os = "dragonfly",
278            target_os = "freebsd",
279            target_os = "fuchsia",
280            target_os = "illumos",
281            target_os = "linux",
282            target_os = "netbsd",
283            target_os = "openbsd",
284            target_os = "cygwin",
285        )))]
286        {
287            let (socket, addr) = self.accept_raw()?;
288            let socket = set_common_accept_flags(socket)?;
289            // `set_common_flags` does not disable inheritance on Windows because `Socket::new`
290            // unlike `accept` is able to create the socket with inheritance disabled.
291            #[cfg(windows)]
292            socket._set_no_inherit(true)?;
293            Ok((socket, addr))
294        }
295    }
296
297    /// Accept a new incoming connection from this listener.
298    ///
299    /// This function directly corresponds to the `accept(2)` function on
300    /// Windows and Unix.
301    pub fn accept_raw(&self) -> io::Result<(Socket, SockAddr)> {
302        sys::accept(self.as_raw()).map(|(inner, addr)| (Socket::from_raw(inner), addr))
303    }
304
305    /// Returns the socket address of the local half of this socket.
306    ///
307    /// This function directly corresponds to the `getsockname(2)` function on
308    /// Windows and Unix.
309    #[doc = man_links!(getsockname(2))]
310    ///
311    /// # Notes
312    ///
313    /// Depending on the OS this may return an error if the socket is not
314    /// [bound].
315    ///
316    /// [bound]: Socket::bind
317    pub fn local_addr(&self) -> io::Result<SockAddr> {
318        sys::getsockname(self.as_raw())
319    }
320
321    /// Returns the socket address of the remote peer of this socket.
322    ///
323    /// This function directly corresponds to the `getpeername(2)` function on
324    /// Windows and Unix.
325    #[doc = man_links!(getpeername(2))]
326    ///
327    /// # Notes
328    ///
329    /// This returns an error if the socket is not [`connect`ed].
330    ///
331    /// [`connect`ed]: Socket::connect
332    pub fn peer_addr(&self) -> io::Result<SockAddr> {
333        sys::getpeername(self.as_raw())
334    }
335
336    /// Returns the [`Type`] of this socket by checking the `SO_TYPE` option on
337    /// this socket.
338    pub fn r#type(&self) -> io::Result<Type> {
339        unsafe { getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_TYPE).map(Type) }
340    }
341
342    /// Creates a new independently owned handle to the underlying socket.
343    ///
344    /// # Notes
345    ///
346    /// On Unix this uses `F_DUPFD_CLOEXEC` and thus sets the `FD_CLOEXEC` on
347    /// the returned socket.
348    ///
349    /// On Windows this uses `WSA_FLAG_NO_HANDLE_INHERIT` setting inheriting to
350    /// false.
351    ///
352    /// On Windows this can **not** be used function cannot be used on a
353    /// QOS-enabled socket, see
354    /// <https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsaduplicatesocketw>.
355    #[cfg(not(target_os = "wasi"))]
356    pub fn try_clone(&self) -> io::Result<Socket> {
357        sys::try_clone(self.as_raw()).map(Socket::from_raw)
358    }
359
360    /// Returns true if this socket is set to nonblocking mode, false otherwise.
361    ///
362    /// # Notes
363    ///
364    /// On Unix this corresponds to calling `fcntl` returning the value of
365    /// `O_NONBLOCK`.
366    ///
367    /// On Windows it is not possible retrieve the nonblocking mode status.
368    #[cfg(all(
369        feature = "all",
370        any(unix, all(target_os = "wasi", not(target_env = "p1")))
371    ))]
372    pub fn nonblocking(&self) -> io::Result<bool> {
373        sys::nonblocking(self.as_raw())
374    }
375
376    /// Moves this socket into or out of nonblocking mode.
377    ///
378    /// # Notes
379    ///
380    /// On Unix this corresponds to calling `fcntl` (un)setting `O_NONBLOCK`.
381    ///
382    /// On Windows this corresponds to calling `ioctlsocket` (un)setting
383    /// `FIONBIO`.
384    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
385        sys::set_nonblocking(self.as_raw(), nonblocking)
386    }
387
388    /// Shuts down the read, write, or both halves of this connection.
389    ///
390    /// This function will cause all pending and future I/O on the specified
391    /// portions to return immediately with an appropriate value.
392    #[doc = man_links!(shutdown(2))]
393    pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
394        sys::shutdown(self.as_raw(), how)
395    }
396
397    /// Receives data on the socket from the remote address to which it is
398    /// connected.
399    ///
400    /// The [`connect`] method will connect this socket to a remote address.
401    /// This method might fail if the socket is not connected.
402    #[doc = man_links!(recv(2))]
403    ///
404    /// [`connect`]: Socket::connect
405    ///
406    /// # Safety
407    ///
408    /// Normally casting a `&mut [u8]` to `&mut [MaybeUninit<u8>]` would be
409    /// unsound, as that allows us to write uninitialised bytes to the buffer.
410    /// However this implementation promises to not write uninitialised bytes to
411    /// the `buf`fer and passes it directly to `recv(2)` system call. This
412    /// promise ensures that this function can be called using a `buf`fer of
413    /// type `&mut [u8]`.
414    ///
415    /// Note that the [`io::Read::read`] implementation calls this function with
416    /// a `buf`fer of type `&mut [u8]`, allowing initialised buffers to be used
417    /// without using `unsafe`.
418    pub fn recv(&self, buf: &mut [MaybeUninit<u8>]) -> io::Result<usize> {
419        self.recv_with_flags(buf, 0)
420    }
421
422    /// Receives out-of-band (OOB) data on the socket from the remote address to
423    /// which it is connected by setting the `MSG_OOB` flag for this call.
424    ///
425    /// For more information, see [`recv`], [`out_of_band_inline`].
426    ///
427    /// [`recv`]: Socket::recv
428    /// [`out_of_band_inline`]: Socket::out_of_band_inline
429    #[cfg_attr(target_os = "redox", allow(rustdoc::broken_intra_doc_links))]
430    #[cfg(not(target_os = "wasi"))]
431    pub fn recv_out_of_band(&self, buf: &mut [MaybeUninit<u8>]) -> io::Result<usize> {
432        self.recv_with_flags(buf, sys::MSG_OOB)
433    }
434
435    /// Identical to [`recv`] but allows for specification of arbitrary flags to
436    /// the underlying `recv` call.
437    ///
438    /// [`recv`]: Socket::recv
439    pub fn recv_with_flags(
440        &self,
441        buf: &mut [MaybeUninit<u8>],
442        flags: sys::c_int,
443    ) -> io::Result<usize> {
444        sys::recv(self.as_raw(), buf, flags)
445    }
446
447    /// Receives data on the socket from the remote address to which it is
448    /// connected. Unlike [`recv`] this allows passing multiple buffers.
449    ///
450    /// The [`connect`] method will connect this socket to a remote address.
451    /// This method might fail if the socket is not connected.
452    ///
453    /// In addition to the number of bytes read, this function returns the flags
454    /// for the received message. See [`RecvFlags`] for more information about
455    /// the returned flags.
456    #[doc = man_links!(recvmsg(2))]
457    ///
458    /// [`recv`]: Socket::recv
459    /// [`connect`]: Socket::connect
460    ///
461    /// # Safety
462    ///
463    /// Normally casting a `IoSliceMut` to `MaybeUninitSlice` would be unsound,
464    /// as that allows us to write uninitialised bytes to the buffer. However
465    /// this implementation promises to not write uninitialised bytes to the
466    /// `bufs` and passes it directly to `recvmsg(2)` system call. This promise
467    /// ensures that this function can be called using `bufs` of type `&mut
468    /// [IoSliceMut]`.
469    ///
470    /// Note that the [`io::Read::read_vectored`] implementation calls this
471    /// function with `buf`s of type `&mut [IoSliceMut]`, allowing initialised
472    /// buffers to be used without using `unsafe`.
473    #[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
474    pub fn recv_vectored(
475        &self,
476        bufs: &mut [MaybeUninitSlice<'_>],
477    ) -> io::Result<(usize, RecvFlags)> {
478        self.recv_vectored_with_flags(bufs, 0)
479    }
480
481    /// Identical to [`recv_vectored`] but allows for specification of arbitrary
482    /// flags to the underlying `recvmsg`/`WSARecv` call.
483    ///
484    /// [`recv_vectored`]: Socket::recv_vectored
485    ///
486    /// # Safety
487    ///
488    /// `recv_from_vectored` makes the same safety guarantees regarding `bufs`
489    /// as [`recv_vectored`].
490    ///
491    /// [`recv_vectored`]: Socket::recv_vectored
492    #[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
493    pub fn recv_vectored_with_flags(
494        &self,
495        bufs: &mut [MaybeUninitSlice<'_>],
496        flags: c_int,
497    ) -> io::Result<(usize, RecvFlags)> {
498        sys::recv_vectored(self.as_raw(), bufs, flags)
499    }
500
501    /// Receives data on the socket from the remote address to which it is
502    /// connected, without removing that data from the queue. On success,
503    /// returns the number of bytes peeked.
504    ///
505    /// Successive calls return the same data. This is accomplished by passing
506    /// `MSG_PEEK` as a flag to the underlying `recv` system call.
507    ///
508    /// # Safety
509    ///
510    /// `peek` makes the same safety guarantees regarding the `buf`fer as
511    /// [`recv`].
512    ///
513    /// [`recv`]: Socket::recv
514    pub fn peek(&self, buf: &mut [MaybeUninit<u8>]) -> io::Result<usize> {
515        self.recv_with_flags(buf, sys::MSG_PEEK)
516    }
517
518    /// Receives data from the socket. On success, returns the number of bytes
519    /// read and the address from whence the data came.
520    #[doc = man_links!(recvfrom(2))]
521    ///
522    /// # Safety
523    ///
524    /// `recv_from` makes the same safety guarantees regarding the `buf`fer as
525    /// [`recv`].
526    ///
527    /// [`recv`]: Socket::recv
528    pub fn recv_from(&self, buf: &mut [MaybeUninit<u8>]) -> io::Result<(usize, SockAddr)> {
529        self.recv_from_with_flags(buf, 0)
530    }
531
532    /// Identical to [`recv_from`] but allows for specification of arbitrary
533    /// flags to the underlying `recvfrom` call.
534    ///
535    /// [`recv_from`]: Socket::recv_from
536    pub fn recv_from_with_flags(
537        &self,
538        buf: &mut [MaybeUninit<u8>],
539        flags: c_int,
540    ) -> io::Result<(usize, SockAddr)> {
541        sys::recv_from(self.as_raw(), buf, flags)
542    }
543
544    /// Receives data from the socket. Returns the amount of bytes read, the
545    /// [`RecvFlags`] and the remote address from the data is coming. Unlike
546    /// [`recv_from`] this allows passing multiple buffers.
547    #[doc = man_links!(recvmsg(2))]
548    ///
549    /// [`recv_from`]: Socket::recv_from
550    ///
551    /// # Safety
552    ///
553    /// `recv_from_vectored` makes the same safety guarantees regarding `bufs`
554    /// as [`recv_vectored`].
555    ///
556    /// [`recv_vectored`]: Socket::recv_vectored
557    #[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
558    pub fn recv_from_vectored(
559        &self,
560        bufs: &mut [MaybeUninitSlice<'_>],
561    ) -> io::Result<(usize, RecvFlags, SockAddr)> {
562        self.recv_from_vectored_with_flags(bufs, 0)
563    }
564
565    /// Identical to [`recv_from_vectored`] but allows for specification of
566    /// arbitrary flags to the underlying `recvmsg`/`WSARecvFrom` call.
567    ///
568    /// [`recv_from_vectored`]: Socket::recv_from_vectored
569    ///
570    /// # Safety
571    ///
572    /// `recv_from_vectored` makes the same safety guarantees regarding `bufs`
573    /// as [`recv_vectored`].
574    ///
575    /// [`recv_vectored`]: Socket::recv_vectored
576    #[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
577    pub fn recv_from_vectored_with_flags(
578        &self,
579        bufs: &mut [MaybeUninitSlice<'_>],
580        flags: c_int,
581    ) -> io::Result<(usize, RecvFlags, SockAddr)> {
582        sys::recv_from_vectored(self.as_raw(), bufs, flags)
583    }
584
585    /// Receives data from the socket, without removing it from the queue.
586    ///
587    /// Successive calls return the same data. This is accomplished by passing
588    /// `MSG_PEEK` as a flag to the underlying `recvfrom` system call.
589    ///
590    /// On success, returns the number of bytes peeked and the address from
591    /// whence the data came.
592    ///
593    /// # Safety
594    ///
595    /// `peek_from` makes the same safety guarantees regarding the `buf`fer as
596    /// [`recv`].
597    ///
598    /// # Note: Datagram Sockets
599    /// For datagram sockets, the behavior of this method when `buf` is smaller than
600    /// the datagram at the head of the receive queue differs between Windows and
601    /// Unix-like platforms (Linux, macOS, BSDs, etc: colloquially termed "*nix").
602    ///
603    /// On *nix platforms, the datagram is truncated to the length of `buf`.
604    ///
605    /// On Windows, an error corresponding to `WSAEMSGSIZE` will be returned.
606    ///
607    /// For consistency between platforms, be sure to provide a sufficiently large buffer to avoid
608    /// truncation; the exact size required depends on the underlying protocol.
609    ///
610    /// If you just want to know the sender of the data, try [`peek_sender`].
611    ///
612    /// [`recv`]: Socket::recv
613    /// [`peek_sender`]: Socket::peek_sender
614    pub fn peek_from(&self, buf: &mut [MaybeUninit<u8>]) -> io::Result<(usize, SockAddr)> {
615        self.recv_from_with_flags(buf, sys::MSG_PEEK)
616    }
617
618    /// Retrieve the sender for the data at the head of the receive queue.
619    ///
620    /// This is equivalent to calling [`peek_from`] with a zero-sized buffer,
621    /// but suppresses the `WSAEMSGSIZE` error on Windows.
622    ///
623    /// [`peek_from`]: Socket::peek_from
624    pub fn peek_sender(&self) -> io::Result<SockAddr> {
625        sys::peek_sender(self.as_raw())
626    }
627
628    /// Receive a message from a socket using a message structure.
629    ///
630    /// This is not supported on Windows as calling `WSARecvMsg` (the `recvmsg`
631    /// equivalent) is not straight forward on Windows. See
632    /// <https://github.com/microsoft/Windows-classic-samples/blob/7cbd99ac1d2b4a0beffbaba29ea63d024ceff700/Samples/Win7Samples/netds/winsock/recvmsg/rmmc.cpp>
633    /// for an example (in C++).
634    #[doc = man_links!(recvmsg(2))]
635    #[cfg(all(unix, not(any(target_os = "redox", target_os = "horizon"))))]
636    pub fn recvmsg(&self, msg: &mut MsgHdrMut<'_, '_, '_>, flags: sys::c_int) -> io::Result<usize> {
637        sys::recvmsg(self.as_raw(), msg, flags)
638    }
639
640    /// Sends data on the socket to a connected peer.
641    ///
642    /// This is typically used on TCP sockets or datagram sockets which have
643    /// been connected.
644    ///
645    /// On success returns the number of bytes that were sent.
646    #[doc = man_links!(send(2))]
647    pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
648        self.send_with_flags(buf, 0)
649    }
650
651    /// Identical to [`send`] but allows for specification of arbitrary flags to the underlying
652    /// `send` call.
653    ///
654    /// [`send`]: Socket::send
655    pub fn send_with_flags(&self, buf: &[u8], flags: c_int) -> io::Result<usize> {
656        sys::send(self.as_raw(), buf, flags)
657    }
658
659    /// Send data to the connected peer. Returns the amount of bytes written.
660    #[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
661    pub fn send_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
662        self.send_vectored_with_flags(bufs, 0)
663    }
664
665    /// Identical to [`send_vectored`] but allows for specification of arbitrary
666    /// flags to the underlying `sendmsg`/`WSASend` call.
667    #[doc = man_links!(sendmsg(2))]
668    ///
669    /// [`send_vectored`]: Socket::send_vectored
670    #[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
671    pub fn send_vectored_with_flags(
672        &self,
673        bufs: &[IoSlice<'_>],
674        flags: c_int,
675    ) -> io::Result<usize> {
676        sys::send_vectored(self.as_raw(), bufs, flags)
677    }
678
679    /// Sends out-of-band (OOB) data on the socket to connected peer
680    /// by setting the `MSG_OOB` flag for this call.
681    ///
682    /// For more information, see [`send`], [`out_of_band_inline`].
683    ///
684    /// [`send`]: Socket::send
685    /// [`out_of_band_inline`]: Socket::out_of_band_inline
686    #[cfg_attr(target_os = "redox", allow(rustdoc::broken_intra_doc_links))]
687    #[cfg(not(target_os = "wasi"))]
688    pub fn send_out_of_band(&self, buf: &[u8]) -> io::Result<usize> {
689        self.send_with_flags(buf, sys::MSG_OOB)
690    }
691
692    /// Sends data on the socket to the given address. On success, returns the
693    /// number of bytes written.
694    ///
695    /// This is typically used on UDP or datagram-oriented sockets.
696    #[doc = man_links!(sendto(2))]
697    pub fn send_to(&self, buf: &[u8], addr: &SockAddr) -> io::Result<usize> {
698        self.send_to_with_flags(buf, addr, 0)
699    }
700
701    /// Identical to [`send_to`] but allows for specification of arbitrary flags
702    /// to the underlying `sendto` call.
703    ///
704    /// [`send_to`]: Socket::send_to
705    pub fn send_to_with_flags(
706        &self,
707        buf: &[u8],
708        addr: &SockAddr,
709        flags: c_int,
710    ) -> io::Result<usize> {
711        sys::send_to(self.as_raw(), buf, addr, flags)
712    }
713
714    /// Send data to a peer listening on `addr`. Returns the amount of bytes
715    /// written.
716    #[doc = man_links!(sendmsg(2))]
717    #[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
718    pub fn send_to_vectored(&self, bufs: &[IoSlice<'_>], addr: &SockAddr) -> io::Result<usize> {
719        self.send_to_vectored_with_flags(bufs, addr, 0)
720    }
721
722    /// Identical to [`send_to_vectored`] but allows for specification of
723    /// arbitrary flags to the underlying `sendmsg`/`WSASendTo` call.
724    ///
725    /// [`send_to_vectored`]: Socket::send_to_vectored
726    #[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
727    pub fn send_to_vectored_with_flags(
728        &self,
729        bufs: &[IoSlice<'_>],
730        addr: &SockAddr,
731        flags: c_int,
732    ) -> io::Result<usize> {
733        sys::send_to_vectored(self.as_raw(), bufs, addr, flags)
734    }
735
736    /// Send a message on a socket using a message structure.
737    #[doc = man_links!(sendmsg(2))]
738    #[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
739    pub fn sendmsg(&self, msg: &MsgHdr<'_, '_, '_>, flags: sys::c_int) -> io::Result<usize> {
740        sys::sendmsg(self.as_raw(), msg, flags)
741    }
742}
743
744/// Set `SOCK_CLOEXEC` and `NO_HANDLE_INHERIT` on the `ty`pe on platforms that
745/// support it.
746#[inline(always)]
747const fn set_common_type(ty: Type) -> Type {
748    // On platforms that support it set `SOCK_CLOEXEC`.
749    #[cfg(any(
750        target_os = "android",
751        target_os = "dragonfly",
752        target_os = "freebsd",
753        target_os = "fuchsia",
754        target_os = "hurd",
755        target_os = "illumos",
756        target_os = "linux",
757        target_os = "netbsd",
758        target_os = "openbsd",
759        target_os = "cygwin",
760    ))]
761    let ty = ty._cloexec();
762
763    // On windows set `NO_HANDLE_INHERIT`.
764    #[cfg(windows)]
765    let ty = ty._no_inherit();
766
767    ty
768}
769
770/// Set `FD_CLOEXEC` and `NOSIGPIPE` on the `socket` for platforms that need it.
771///
772/// Sockets created via `accept` should use `set_common_accept_flags` instead.
773fn set_common_flags(socket: Socket) -> io::Result<Socket> {
774    // On platforms that don't have `SOCK_CLOEXEC` use `FD_CLOEXEC`.
775    #[cfg(all(
776        unix,
777        not(any(
778            target_os = "android",
779            target_os = "dragonfly",
780            target_os = "freebsd",
781            target_os = "fuchsia",
782            target_os = "hurd",
783            target_os = "illumos",
784            target_os = "linux",
785            target_os = "netbsd",
786            target_os = "openbsd",
787            target_os = "espidf",
788            target_os = "vita",
789            target_os = "cygwin",
790        ))
791    ))]
792    socket._set_cloexec(true)?;
793
794    // On Apple platforms set `NOSIGPIPE`.
795    #[cfg(any(
796        target_os = "ios",
797        target_os = "visionos",
798        target_os = "macos",
799        target_os = "tvos",
800        target_os = "watchos",
801    ))]
802    socket._set_nosigpipe(true)?;
803
804    Ok(socket)
805}
806
807/// Set `FD_CLOEXEC` on the `socket` for platforms that need it.
808///
809/// Unlike `set_common_flags` we don't set `NOSIGPIPE` as that is inherited from
810/// the listener. Furthermore, attempts to set it on a unix socket domain
811/// results in an error.
812#[cfg(not(any(
813    target_os = "android",
814    target_os = "dragonfly",
815    target_os = "freebsd",
816    target_os = "fuchsia",
817    target_os = "illumos",
818    target_os = "linux",
819    target_os = "netbsd",
820    target_os = "openbsd",
821    target_os = "cygwin",
822)))]
823fn set_common_accept_flags(socket: Socket) -> io::Result<Socket> {
824    // On platforms that don't have `SOCK_CLOEXEC` use `FD_CLOEXEC`.
825    #[cfg(all(
826        unix,
827        not(any(
828            target_os = "android",
829            target_os = "dragonfly",
830            target_os = "freebsd",
831            target_os = "fuchsia",
832            target_os = "hurd",
833            target_os = "illumos",
834            target_os = "linux",
835            target_os = "netbsd",
836            target_os = "openbsd",
837            target_os = "espidf",
838            target_os = "vita",
839            target_os = "cygwin",
840        ))
841    ))]
842    socket._set_cloexec(true)?;
843
844    Ok(socket)
845}
846
847/// A local interface specified by its index or an address assigned to it.
848///
849/// `Index(0)` and `Address(Ipv4Addr::UNSPECIFIED)` are equivalent and indicate
850/// that an appropriate interface should be selected by the system.
851#[cfg(not(any(
852    target_os = "haiku",
853    target_os = "illumos",
854    target_os = "netbsd",
855    target_os = "redox",
856    target_os = "solaris",
857    target_os = "wasi",
858)))]
859#[derive(Debug, Copy, Clone)]
860pub enum InterfaceIndexOrAddress {
861    /// An interface index.
862    Index(u32),
863    /// An address assigned to an interface.
864    Address(Ipv4Addr),
865}
866
867/// Socket options get/set using `SOL_SOCKET`.
868///
869/// Additional documentation can be found in documentation of the OS.
870/// * Linux: <https://man7.org/linux/man-pages/man7/socket.7.html>
871/// * Windows: <https://docs.microsoft.com/en-us/windows/win32/winsock/sol-socket-socket-options>
872impl Socket {
873    /// Get the value of the `SO_BROADCAST` option for this socket.
874    ///
875    /// For more information about this option, see [`set_broadcast`].
876    ///
877    /// [`set_broadcast`]: Socket::set_broadcast
878    pub fn broadcast(&self) -> io::Result<bool> {
879        unsafe {
880            getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_BROADCAST)
881                .map(|broadcast| broadcast != 0)
882        }
883    }
884
885    /// Set the value of the `SO_BROADCAST` option for this socket.
886    ///
887    /// When enabled, this socket is allowed to send packets to a broadcast
888    /// address.
889    pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> {
890        unsafe {
891            setsockopt(
892                self.as_raw(),
893                sys::SOL_SOCKET,
894                sys::SO_BROADCAST,
895                broadcast as c_int,
896            )
897        }
898    }
899
900    /// Get the value of the `SO_ERROR` option on this socket.
901    ///
902    /// This will retrieve the stored error in the underlying socket, clearing
903    /// the field in the process. This can be useful for checking errors between
904    /// calls.
905    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
906        match unsafe { getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_ERROR) } {
907            Ok(0) => Ok(None),
908            Ok(errno) => Ok(Some(io::Error::from_raw_os_error(errno))),
909            Err(err) => Err(err),
910        }
911    }
912
913    /// Get the value of the `SO_KEEPALIVE` option on this socket.
914    ///
915    /// For more information about this option, see [`set_keepalive`].
916    ///
917    /// [`set_keepalive`]: Socket::set_keepalive
918    pub fn keepalive(&self) -> io::Result<bool> {
919        unsafe {
920            getsockopt::<Bool>(self.as_raw(), sys::SOL_SOCKET, sys::SO_KEEPALIVE)
921                .map(|keepalive| keepalive != 0)
922        }
923    }
924
925    /// Set value for the `SO_KEEPALIVE` option on this socket.
926    ///
927    /// Enable sending of keep-alive messages on connection-oriented sockets.
928    pub fn set_keepalive(&self, keepalive: bool) -> io::Result<()> {
929        unsafe {
930            setsockopt(
931                self.as_raw(),
932                sys::SOL_SOCKET,
933                sys::SO_KEEPALIVE,
934                keepalive as c_int,
935            )
936        }
937    }
938
939    /// Get the value of the `SO_LINGER` option on this socket.
940    ///
941    /// For more information about this option, see [`set_linger`].
942    ///
943    /// [`set_linger`]: Socket::set_linger
944    pub fn linger(&self) -> io::Result<Option<Duration>> {
945        unsafe {
946            getsockopt::<sys::linger>(self.as_raw(), sys::SOL_SOCKET, sys::SO_LINGER)
947                .map(from_linger)
948        }
949    }
950
951    /// Set value for the `SO_LINGER` option on this socket.
952    ///
953    /// If `linger` is not `None`, a close(2) or shutdown(2) will not return
954    /// until all queued messages for the socket have been successfully sent or
955    /// the linger timeout has been reached. Otherwise, the call returns
956    /// immediately and the closing is done in the background. When the socket
957    /// is closed as part of exit(2), it always lingers in the background.
958    ///
959    /// # Notes
960    ///
961    /// On most OSs the duration only has a precision of seconds and will be
962    /// silently truncated.
963    ///
964    /// On Apple platforms (e.g. macOS, iOS, etc) this uses `SO_LINGER_SEC`.
965    pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
966        let linger = into_linger(linger);
967        unsafe { setsockopt(self.as_raw(), sys::SOL_SOCKET, sys::SO_LINGER, linger) }
968    }
969
970    /// Get value for the `SO_OOBINLINE` option on this socket.
971    ///
972    /// For more information about this option, see [`set_out_of_band_inline`].
973    ///
974    /// [`set_out_of_band_inline`]: Socket::set_out_of_band_inline
975    #[cfg(not(any(target_os = "redox", target_os = "wasi")))]
976    pub fn out_of_band_inline(&self) -> io::Result<bool> {
977        unsafe {
978            getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_OOBINLINE)
979                .map(|oob_inline| oob_inline != 0)
980        }
981    }
982
983    /// Set value for the `SO_OOBINLINE` option on this socket.
984    ///
985    /// If this option is enabled, out-of-band data is directly placed into the
986    /// receive data stream. Otherwise, out-of-band data is passed only when the
987    /// `MSG_OOB` flag is set during receiving. As per RFC6093, TCP sockets
988    /// using the Urgent mechanism are encouraged to set this flag.
989    #[cfg(not(any(target_os = "redox", target_os = "wasi")))]
990    pub fn set_out_of_band_inline(&self, oob_inline: bool) -> io::Result<()> {
991        unsafe {
992            setsockopt(
993                self.as_raw(),
994                sys::SOL_SOCKET,
995                sys::SO_OOBINLINE,
996                oob_inline as c_int,
997            )
998        }
999    }
1000
1001    /// Get value for the `SO_PASSCRED` option on this socket.
1002    ///
1003    /// For more information about this option, see [`set_passcred`].
1004    ///
1005    /// [`set_passcred`]: Socket::set_passcred
1006    #[cfg(any(target_os = "linux", target_os = "cygwin"))]
1007    pub fn passcred(&self) -> io::Result<bool> {
1008        unsafe {
1009            getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_PASSCRED)
1010                .map(|passcred| passcred != 0)
1011        }
1012    }
1013
1014    /// Set value for the `SO_PASSCRED` option on this socket.
1015    ///
1016    /// If this option is enabled, enables the receiving of the `SCM_CREDENTIALS`
1017    /// control messages.
1018    #[cfg(any(target_os = "linux", target_os = "cygwin"))]
1019    pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
1020        unsafe {
1021            setsockopt(
1022                self.as_raw(),
1023                sys::SOL_SOCKET,
1024                sys::SO_PASSCRED,
1025                passcred as c_int,
1026            )
1027        }
1028    }
1029
1030    /// Get value for the `SO_PRIORITY` option on this socket.
1031    ///
1032    /// For more information about this option, see [`set_priority`].
1033    ///
1034    /// [`set_priority`]: Socket::set_priority
1035    #[cfg(all(
1036        feature = "all",
1037        any(target_os = "linux", target_os = "android", target_os = "fuchsia")
1038    ))]
1039    pub fn priority(&self) -> io::Result<u32> {
1040        unsafe {
1041            getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_PRIORITY)
1042                .map(|prio| prio as u32)
1043        }
1044    }
1045
1046    /// Set value for the `SO_PRIORITY` option on this socket.
1047    ///
1048    /// Packets with a higher priority may be processed earlier depending on the selected device
1049    /// queueing discipline.
1050    #[cfg(all(
1051        feature = "all",
1052        any(target_os = "linux", target_os = "android", target_os = "fuchsia")
1053    ))]
1054    pub fn set_priority(&self, priority: u32) -> io::Result<()> {
1055        unsafe {
1056            setsockopt(
1057                self.as_raw(),
1058                sys::SOL_SOCKET,
1059                sys::SO_PRIORITY,
1060                priority as c_int,
1061            )
1062        }
1063    }
1064
1065    /// Get value for the `SO_RCVBUF` option on this socket.
1066    ///
1067    /// For more information about this option, see [`set_recv_buffer_size`].
1068    ///
1069    /// [`set_recv_buffer_size`]: Socket::set_recv_buffer_size
1070    pub fn recv_buffer_size(&self) -> io::Result<usize> {
1071        unsafe {
1072            getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_RCVBUF)
1073                .map(|size| size as usize)
1074        }
1075    }
1076
1077    /// Set value for the `SO_RCVBUF` option on this socket.
1078    ///
1079    /// Changes the size of the operating system's receive buffer associated
1080    /// with the socket.
1081    pub fn set_recv_buffer_size(&self, size: usize) -> io::Result<()> {
1082        unsafe {
1083            setsockopt(
1084                self.as_raw(),
1085                sys::SOL_SOCKET,
1086                sys::SO_RCVBUF,
1087                size as c_int,
1088            )
1089        }
1090    }
1091
1092    /// Get value for the `SO_RCVTIMEO` option on this socket.
1093    ///
1094    /// If the returned timeout is `None`, then `read` and `recv` calls will
1095    /// block indefinitely.
1096    pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
1097        sys::timeout_opt(self.as_raw(), sys::SOL_SOCKET, sys::SO_RCVTIMEO)
1098    }
1099
1100    /// Set value for the `SO_RCVTIMEO` option on this socket.
1101    ///
1102    /// If `timeout` is `None`, then `read` and `recv` calls will block
1103    /// indefinitely.
1104    pub fn set_read_timeout(&self, duration: Option<Duration>) -> io::Result<()> {
1105        sys::set_timeout_opt(self.as_raw(), sys::SOL_SOCKET, sys::SO_RCVTIMEO, duration)
1106    }
1107
1108    /// Get the value of the `SO_REUSEADDR` option on this socket.
1109    ///
1110    /// For more information about this option, see [`set_reuse_address`].
1111    ///
1112    /// [`set_reuse_address`]: Socket::set_reuse_address
1113    pub fn reuse_address(&self) -> io::Result<bool> {
1114        unsafe {
1115            getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_REUSEADDR)
1116                .map(|reuse| reuse != 0)
1117        }
1118    }
1119
1120    /// Set value for the `SO_REUSEADDR` option on this socket.
1121    ///
1122    /// This indicates that further calls to `bind` may allow reuse of local
1123    /// addresses. For IPv4 sockets this means that a socket may bind even when
1124    /// there's a socket already listening on this port.
1125    pub fn set_reuse_address(&self, reuse: bool) -> io::Result<()> {
1126        unsafe {
1127            setsockopt(
1128                self.as_raw(),
1129                sys::SOL_SOCKET,
1130                sys::SO_REUSEADDR,
1131                reuse as c_int,
1132            )
1133        }
1134    }
1135
1136    /// Get the value of the `SO_SNDBUF` option on this socket.
1137    ///
1138    /// For more information about this option, see [`set_send_buffer_size`].
1139    ///
1140    /// [`set_send_buffer_size`]: Socket::set_send_buffer_size
1141    pub fn send_buffer_size(&self) -> io::Result<usize> {
1142        unsafe {
1143            getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_SNDBUF)
1144                .map(|size| size as usize)
1145        }
1146    }
1147
1148    /// Set value for the `SO_SNDBUF` option on this socket.
1149    ///
1150    /// Changes the size of the operating system's send buffer associated with
1151    /// the socket.
1152    pub fn set_send_buffer_size(&self, size: usize) -> io::Result<()> {
1153        unsafe {
1154            setsockopt(
1155                self.as_raw(),
1156                sys::SOL_SOCKET,
1157                sys::SO_SNDBUF,
1158                size as c_int,
1159            )
1160        }
1161    }
1162
1163    /// Get value for the `SO_SNDTIMEO` option on this socket.
1164    ///
1165    /// If the returned timeout is `None`, then `write` and `send` calls will
1166    /// block indefinitely.
1167    pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
1168        sys::timeout_opt(self.as_raw(), sys::SOL_SOCKET, sys::SO_SNDTIMEO)
1169    }
1170
1171    /// Set value for the `SO_SNDTIMEO` option on this socket.
1172    ///
1173    /// If `timeout` is `None`, then `write` and `send` calls will block
1174    /// indefinitely.
1175    pub fn set_write_timeout(&self, duration: Option<Duration>) -> io::Result<()> {
1176        sys::set_timeout_opt(self.as_raw(), sys::SOL_SOCKET, sys::SO_SNDTIMEO, duration)
1177    }
1178}
1179
1180const fn from_linger(linger: sys::linger) -> Option<Duration> {
1181    if linger.l_onoff == 0 {
1182        None
1183    } else {
1184        Some(Duration::from_secs(linger.l_linger as u64))
1185    }
1186}
1187
1188const fn into_linger(duration: Option<Duration>) -> sys::linger {
1189    match duration {
1190        Some(duration) => sys::linger {
1191            l_onoff: 1,
1192            l_linger: duration.as_secs() as _,
1193        },
1194        None => sys::linger {
1195            l_onoff: 0,
1196            l_linger: 0,
1197        },
1198    }
1199}
1200
1201/// Socket options for IPv4 sockets, get/set using `IPPROTO_IP` or `SOL_IP`.
1202///
1203/// Additional documentation can be found in documentation of the OS.
1204/// * Linux: <https://man7.org/linux/man-pages/man7/ip.7.html>
1205/// * Windows: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options>
1206impl Socket {
1207    /// Get the value of the `IP_HDRINCL` option on this socket.
1208    ///
1209    /// For more information about this option, see [`set_header_included_v4`].
1210    ///
1211    /// [`set_header_included_v4`]: Socket::set_header_included_v4
1212    #[cfg(all(
1213        feature = "all",
1214        not(any(
1215            target_os = "redox",
1216            target_os = "espidf",
1217            target_os = "wasi",
1218            target_os = "horizon"
1219        ))
1220    ))]
1221    pub fn header_included_v4(&self) -> io::Result<bool> {
1222        unsafe {
1223            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_HDRINCL)
1224                .map(|included| included != 0)
1225        }
1226    }
1227
1228    /// Set the value of the `IP_HDRINCL` option on this socket.
1229    ///
1230    /// If enabled, the user supplies an IP header in front of the user data.
1231    /// Valid only for [`SOCK_RAW`] sockets; see [raw(7)] for more information.
1232    /// When this flag is enabled, the values set by `IP_OPTIONS`, [`IP_TTL`],
1233    /// and [`IP_TOS`] are ignored.
1234    ///
1235    /// [`SOCK_RAW`]: Type::RAW
1236    /// [raw(7)]: https://man7.org/linux/man-pages/man7/raw.7.html
1237    /// [`IP_TTL`]: Socket::set_ttl_v4
1238    /// [`IP_TOS`]: Socket::set_tos_v4
1239    #[cfg_attr(
1240        any(target_os = "fuchsia", target_os = "illumos", target_os = "solaris"),
1241        allow(rustdoc::broken_intra_doc_links)
1242    )]
1243    #[cfg(all(
1244        feature = "all",
1245        not(any(
1246            target_os = "redox",
1247            target_os = "espidf",
1248            target_os = "wasi",
1249            target_os = "horizon"
1250        ))
1251    ))]
1252    pub fn set_header_included_v4(&self, included: bool) -> io::Result<()> {
1253        unsafe {
1254            setsockopt(
1255                self.as_raw(),
1256                sys::IPPROTO_IP,
1257                sys::IP_HDRINCL,
1258                included as c_int,
1259            )
1260        }
1261    }
1262
1263    /// Get the value of the `IP_TRANSPARENT` option on this socket.
1264    ///
1265    /// For more information about this option, see [`set_ip_transparent_v4`].
1266    ///
1267    /// [`set_ip_transparent_v4`]: Socket::set_ip_transparent_v4
1268    #[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
1269    pub fn ip_transparent_v4(&self) -> io::Result<bool> {
1270        unsafe {
1271            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, libc::IP_TRANSPARENT)
1272                .map(|transparent| transparent != 0)
1273        }
1274    }
1275
1276    /// Set the value of the `IP_TRANSPARENT` option on this socket.
1277    ///
1278    /// Setting this boolean option enables transparent proxying
1279    /// on this socket.  This socket option allows the calling
1280    /// application to bind to a nonlocal IP address and operate
1281    /// both as a client and a server with the foreign address as
1282    /// the local endpoint.  NOTE: this requires that routing be
1283    /// set up in a way that packets going to the foreign address
1284    /// are routed through the TProxy box (i.e., the system
1285    /// hosting the application that employs the IP_TRANSPARENT
1286    /// socket option).  Enabling this socket option requires
1287    /// superuser privileges (the `CAP_NET_ADMIN` capability).
1288    ///
1289    /// TProxy redirection with the iptables TPROXY target also
1290    /// requires that this option be set on the redirected socket.
1291    #[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
1292    pub fn set_ip_transparent_v4(&self, transparent: bool) -> io::Result<()> {
1293        unsafe {
1294            setsockopt(
1295                self.as_raw(),
1296                sys::IPPROTO_IP,
1297                libc::IP_TRANSPARENT,
1298                transparent as c_int,
1299            )
1300        }
1301    }
1302
1303    /// Join a multicast group using `IP_ADD_MEMBERSHIP` option on this socket.
1304    ///
1305    /// This function specifies a new multicast group for this socket to join.
1306    /// The address must be a valid multicast address, and `interface` is the
1307    /// address of the local interface with which the system should join the
1308    /// multicast group. If it's [`Ipv4Addr::UNSPECIFIED`] (`INADDR_ANY`) then
1309    /// an appropriate interface is chosen by the system.
1310    pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
1311        let mreq = sys::IpMreq {
1312            imr_multiaddr: sys::to_in_addr(multiaddr),
1313            imr_interface: sys::to_in_addr(interface),
1314        };
1315        unsafe { setsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_ADD_MEMBERSHIP, mreq) }
1316    }
1317
1318    /// Leave a multicast group using `IP_DROP_MEMBERSHIP` option on this socket.
1319    ///
1320    /// For more information about this option, see [`join_multicast_v4`].
1321    ///
1322    /// [`join_multicast_v4`]: Socket::join_multicast_v4
1323    pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
1324        let mreq = sys::IpMreq {
1325            imr_multiaddr: sys::to_in_addr(multiaddr),
1326            imr_interface: sys::to_in_addr(interface),
1327        };
1328        unsafe {
1329            setsockopt(
1330                self.as_raw(),
1331                sys::IPPROTO_IP,
1332                sys::IP_DROP_MEMBERSHIP,
1333                mreq,
1334            )
1335        }
1336    }
1337
1338    /// Join a multicast group using `IP_ADD_MEMBERSHIP` option on this socket.
1339    ///
1340    /// This function specifies a new multicast group for this socket to join.
1341    /// The address must be a valid multicast address, and `interface` specifies
1342    /// the local interface with which the system should join the multicast
1343    /// group. See [`InterfaceIndexOrAddress`].
1344    #[cfg(not(any(
1345        target_os = "aix",
1346        target_os = "haiku",
1347        target_os = "illumos",
1348        target_os = "netbsd",
1349        target_os = "openbsd",
1350        target_os = "redox",
1351        target_os = "solaris",
1352        target_os = "nto",
1353        target_os = "espidf",
1354        target_os = "vita",
1355        target_os = "cygwin",
1356        target_os = "wasi",
1357        target_os = "horizon"
1358    )))]
1359    pub fn join_multicast_v4_n(
1360        &self,
1361        multiaddr: &Ipv4Addr,
1362        interface: &InterfaceIndexOrAddress,
1363    ) -> io::Result<()> {
1364        let mreqn = sys::to_mreqn(multiaddr, interface);
1365        unsafe {
1366            setsockopt(
1367                self.as_raw(),
1368                sys::IPPROTO_IP,
1369                sys::IP_ADD_MEMBERSHIP,
1370                mreqn,
1371            )
1372        }
1373    }
1374
1375    /// Leave a multicast group using `IP_DROP_MEMBERSHIP` option on this socket.
1376    ///
1377    /// For more information about this option, see [`join_multicast_v4_n`].
1378    ///
1379    /// [`join_multicast_v4_n`]: Socket::join_multicast_v4_n
1380    #[cfg(not(any(
1381        target_os = "aix",
1382        target_os = "haiku",
1383        target_os = "illumos",
1384        target_os = "netbsd",
1385        target_os = "openbsd",
1386        target_os = "redox",
1387        target_os = "solaris",
1388        target_os = "nto",
1389        target_os = "espidf",
1390        target_os = "vita",
1391        target_os = "cygwin",
1392        target_os = "wasi",
1393        target_os = "horizon"
1394    )))]
1395    pub fn leave_multicast_v4_n(
1396        &self,
1397        multiaddr: &Ipv4Addr,
1398        interface: &InterfaceIndexOrAddress,
1399    ) -> io::Result<()> {
1400        let mreqn = sys::to_mreqn(multiaddr, interface);
1401        unsafe {
1402            setsockopt(
1403                self.as_raw(),
1404                sys::IPPROTO_IP,
1405                sys::IP_DROP_MEMBERSHIP,
1406                mreqn,
1407            )
1408        }
1409    }
1410
1411    /// Join a multicast SSM channel using `IP_ADD_SOURCE_MEMBERSHIP` option on this socket.
1412    ///
1413    /// This function specifies a new multicast channel for this socket to join.
1414    /// The group must be a valid SSM group address, the source must be the address of the sender
1415    /// and `interface` is the address of the local interface with which the system should join the
1416    /// multicast group. If it's [`Ipv4Addr::UNSPECIFIED`] (`INADDR_ANY`) then
1417    /// an appropriate interface is chosen by the system.
1418    #[cfg(not(any(
1419        target_os = "dragonfly",
1420        target_os = "haiku",
1421        target_os = "hurd",
1422        target_os = "netbsd",
1423        target_os = "openbsd",
1424        target_os = "redox",
1425        target_os = "fuchsia",
1426        target_os = "nto",
1427        target_os = "espidf",
1428        target_os = "vita",
1429        target_os = "wasi",
1430        target_os = "horizon"
1431    )))]
1432    pub fn join_ssm_v4(
1433        &self,
1434        source: &Ipv4Addr,
1435        group: &Ipv4Addr,
1436        interface: &Ipv4Addr,
1437    ) -> io::Result<()> {
1438        let mreqs = sys::IpMreqSource {
1439            imr_multiaddr: sys::to_in_addr(group),
1440            imr_interface: sys::to_in_addr(interface),
1441            imr_sourceaddr: sys::to_in_addr(source),
1442        };
1443        unsafe {
1444            setsockopt(
1445                self.as_raw(),
1446                sys::IPPROTO_IP,
1447                sys::IP_ADD_SOURCE_MEMBERSHIP,
1448                mreqs,
1449            )
1450        }
1451    }
1452
1453    /// Leave a multicast group using `IP_DROP_SOURCE_MEMBERSHIP` option on this socket.
1454    ///
1455    /// For more information about this option, see [`join_ssm_v4`].
1456    ///
1457    /// [`join_ssm_v4`]: Socket::join_ssm_v4
1458    #[cfg(not(any(
1459        target_os = "dragonfly",
1460        target_os = "haiku",
1461        target_os = "hurd",
1462        target_os = "netbsd",
1463        target_os = "openbsd",
1464        target_os = "redox",
1465        target_os = "fuchsia",
1466        target_os = "nto",
1467        target_os = "espidf",
1468        target_os = "vita",
1469        target_os = "wasi",
1470        target_os = "horizon"
1471    )))]
1472    pub fn leave_ssm_v4(
1473        &self,
1474        source: &Ipv4Addr,
1475        group: &Ipv4Addr,
1476        interface: &Ipv4Addr,
1477    ) -> io::Result<()> {
1478        let mreqs = sys::IpMreqSource {
1479            imr_multiaddr: sys::to_in_addr(group),
1480            imr_interface: sys::to_in_addr(interface),
1481            imr_sourceaddr: sys::to_in_addr(source),
1482        };
1483        unsafe {
1484            setsockopt(
1485                self.as_raw(),
1486                sys::IPPROTO_IP,
1487                sys::IP_DROP_SOURCE_MEMBERSHIP,
1488                mreqs,
1489            )
1490        }
1491    }
1492
1493    /// Get the value of the `IP_MULTICAST_ALL` option for this socket.
1494    ///
1495    /// For more information about this option, see [`set_multicast_all_v4`].
1496    ///
1497    /// [`set_multicast_all_v4`]: Socket::set_multicast_all_v4
1498    #[cfg(all(feature = "all", target_os = "linux"))]
1499    pub fn multicast_all_v4(&self) -> io::Result<bool> {
1500        unsafe {
1501            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, libc::IP_MULTICAST_ALL)
1502                .map(|all| all != 0)
1503        }
1504    }
1505
1506    /// Set the value of the `IP_MULTICAST_ALL` option for this socket.
1507    ///
1508    /// This option can be used to modify the delivery policy of
1509    /// multicast messages.  The argument is a boolean
1510    /// (defaults to true).  If set to true, the socket will receive
1511    /// messages from all the groups that have been joined
1512    /// globally on the whole system.  Otherwise, it will deliver
1513    /// messages only from the groups that have been explicitly
1514    /// joined (for example via the `IP_ADD_MEMBERSHIP` option) on
1515    /// this particular socket.
1516    #[cfg(all(feature = "all", target_os = "linux"))]
1517    pub fn set_multicast_all_v4(&self, all: bool) -> io::Result<()> {
1518        unsafe {
1519            setsockopt(
1520                self.as_raw(),
1521                sys::IPPROTO_IP,
1522                libc::IP_MULTICAST_ALL,
1523                all as c_int,
1524            )
1525        }
1526    }
1527
1528    /// Get the value of the `IP_MULTICAST_IF` option for this socket.
1529    ///
1530    /// For more information about this option, see [`set_multicast_if_v4`].
1531    ///
1532    /// [`set_multicast_if_v4`]: Socket::set_multicast_if_v4
1533    #[cfg(not(target_os = "wasi"))]
1534    pub fn multicast_if_v4(&self) -> io::Result<Ipv4Addr> {
1535        unsafe {
1536            getsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_MULTICAST_IF).map(sys::from_in_addr)
1537        }
1538    }
1539
1540    /// Set the value of the `IP_MULTICAST_IF` option for this socket.
1541    ///
1542    /// Specifies the interface to use for routing multicast packets.
1543    #[cfg(not(target_os = "wasi"))]
1544    pub fn set_multicast_if_v4(&self, interface: &Ipv4Addr) -> io::Result<()> {
1545        let interface = sys::to_in_addr(interface);
1546        unsafe {
1547            setsockopt(
1548                self.as_raw(),
1549                sys::IPPROTO_IP,
1550                sys::IP_MULTICAST_IF,
1551                interface,
1552            )
1553        }
1554    }
1555
1556    /// Get the value of the `IP_MULTICAST_LOOP` option for this socket.
1557    ///
1558    /// For more information about this option, see [`set_multicast_loop_v4`].
1559    ///
1560    /// [`set_multicast_loop_v4`]: Socket::set_multicast_loop_v4
1561    pub fn multicast_loop_v4(&self) -> io::Result<bool> {
1562        unsafe {
1563            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_MULTICAST_LOOP)
1564                .map(|loop_v4| loop_v4 != 0)
1565        }
1566    }
1567
1568    /// Set the value of the `IP_MULTICAST_LOOP` option for this socket.
1569    ///
1570    /// If enabled, multicast packets will be looped back to the local socket.
1571    /// Note that this may not have any affect on IPv6 sockets.
1572    pub fn set_multicast_loop_v4(&self, loop_v4: bool) -> io::Result<()> {
1573        unsafe {
1574            setsockopt(
1575                self.as_raw(),
1576                sys::IPPROTO_IP,
1577                sys::IP_MULTICAST_LOOP,
1578                loop_v4 as c_int,
1579            )
1580        }
1581    }
1582
1583    /// Get the value of the `IP_MULTICAST_TTL` option for this socket.
1584    ///
1585    /// For more information about this option, see [`set_multicast_ttl_v4`].
1586    ///
1587    /// [`set_multicast_ttl_v4`]: Socket::set_multicast_ttl_v4
1588    pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
1589        unsafe {
1590            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_MULTICAST_TTL)
1591                .map(|ttl| ttl as u32)
1592        }
1593    }
1594
1595    /// Set the value of the `IP_MULTICAST_TTL` option for this socket.
1596    ///
1597    /// Indicates the time-to-live value of outgoing multicast packets for
1598    /// this socket. The default value is 1 which means that multicast packets
1599    /// don't leave the local network unless explicitly requested.
1600    ///
1601    /// Note that this may not have any affect on IPv6 sockets.
1602    pub fn set_multicast_ttl_v4(&self, ttl: u32) -> io::Result<()> {
1603        unsafe {
1604            setsockopt(
1605                self.as_raw(),
1606                sys::IPPROTO_IP,
1607                sys::IP_MULTICAST_TTL,
1608                ttl as c_int,
1609            )
1610        }
1611    }
1612
1613    /// Get the value of the `IP_TTL` option for this socket.
1614    ///
1615    /// For more information about this option, see [`set_ttl_v4`].
1616    ///
1617    /// [`set_ttl_v4`]: Socket::set_ttl_v4
1618    pub fn ttl_v4(&self) -> io::Result<u32> {
1619        unsafe {
1620            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_TTL).map(|ttl| ttl as u32)
1621        }
1622    }
1623
1624    /// Set the value of the `IP_TTL` option for this socket.
1625    ///
1626    /// This value sets the time-to-live field that is used in every packet sent
1627    /// from this socket.
1628    pub fn set_ttl_v4(&self, ttl: u32) -> io::Result<()> {
1629        unsafe { setsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_TTL, ttl as c_int) }
1630    }
1631
1632    /// Set the value of the `IP_TOS` option for this socket.
1633    ///
1634    /// This value sets the type-of-service field that is used in every packet
1635    /// sent from this socket.
1636    ///
1637    /// NOTE: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options>
1638    /// documents that not all versions of windows support `IP_TOS`.
1639    #[cfg(not(any(
1640        target_os = "fuchsia",
1641        target_os = "redox",
1642        target_os = "solaris",
1643        target_os = "illumos",
1644        target_os = "haiku",
1645        target_os = "wasi",
1646    )))]
1647    pub fn set_tos_v4(&self, tos: u32) -> io::Result<()> {
1648        unsafe { setsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_TOS, tos as c_int) }
1649    }
1650
1651    /// Get the value of the `IP_TOS` option for this socket.
1652    ///
1653    /// For more information about this option, see [`set_tos_v4`].
1654    ///
1655    /// NOTE: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options>
1656    /// documents that not all versions of windows support `IP_TOS`.
1657    ///
1658    /// [`set_tos_v4`]: Socket::set_tos_v4
1659    #[cfg(not(any(
1660        target_os = "fuchsia",
1661        target_os = "redox",
1662        target_os = "solaris",
1663        target_os = "illumos",
1664        target_os = "haiku",
1665        target_os = "wasi",
1666    )))]
1667    pub fn tos_v4(&self) -> io::Result<u32> {
1668        unsafe {
1669            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_TOS).map(|tos| tos as u32)
1670        }
1671    }
1672
1673    /// Set the value of the `IP_RECVTOS` option for this socket.
1674    ///
1675    /// If enabled, the `IP_TOS` ancillary message is passed with
1676    /// incoming packets. It contains a byte which specifies the
1677    /// Type of Service/Precedence field of the packet header.
1678    #[cfg(not(any(
1679        target_os = "aix",
1680        target_os = "dragonfly",
1681        target_os = "fuchsia",
1682        target_os = "hurd",
1683        target_os = "illumos",
1684        target_os = "netbsd",
1685        target_os = "openbsd",
1686        target_os = "redox",
1687        target_os = "solaris",
1688        target_os = "haiku",
1689        target_os = "nto",
1690        target_os = "espidf",
1691        target_os = "vita",
1692        target_os = "cygwin",
1693        target_os = "wasi",
1694        target_os = "horizon"
1695    )))]
1696    pub fn set_recv_tos_v4(&self, recv_tos: bool) -> io::Result<()> {
1697        unsafe {
1698            setsockopt(
1699                self.as_raw(),
1700                sys::IPPROTO_IP,
1701                sys::IP_RECVTOS,
1702                recv_tos as c_int,
1703            )
1704        }
1705    }
1706
1707    /// Get the value of the `IP_RECVTOS` option for this socket.
1708    ///
1709    /// For more information about this option, see [`set_recv_tos_v4`].
1710    ///
1711    /// [`set_recv_tos_v4`]: Socket::set_recv_tos_v4
1712    #[cfg(not(any(
1713        target_os = "aix",
1714        target_os = "dragonfly",
1715        target_os = "fuchsia",
1716        target_os = "hurd",
1717        target_os = "illumos",
1718        target_os = "netbsd",
1719        target_os = "openbsd",
1720        target_os = "redox",
1721        target_os = "solaris",
1722        target_os = "haiku",
1723        target_os = "nto",
1724        target_os = "espidf",
1725        target_os = "vita",
1726        target_os = "cygwin",
1727        target_os = "wasi",
1728        target_os = "horizon"
1729    )))]
1730    pub fn recv_tos_v4(&self) -> io::Result<bool> {
1731        unsafe {
1732            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_RECVTOS)
1733                .map(|recv_tos| recv_tos > 0)
1734        }
1735    }
1736
1737    /// Get the value for the `SO_ORIGINAL_DST` option on this socket.
1738    #[cfg(all(
1739        feature = "all",
1740        any(
1741            target_os = "android",
1742            target_os = "fuchsia",
1743            target_os = "linux",
1744            target_os = "windows",
1745        )
1746    ))]
1747    pub fn original_dst_v4(&self) -> io::Result<SockAddr> {
1748        sys::original_dst_v4(self.as_raw())
1749    }
1750}
1751
1752/// Socket options for IPv6 sockets, get/set using `IPPROTO_IPV6` or `SOL_IPV6`.
1753///
1754/// Additional documentation can be found in documentation of the OS.
1755/// * Linux: <https://man7.org/linux/man-pages/man7/ipv6.7.html>
1756/// * Windows: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ipv6-socket-options>
1757impl Socket {
1758    /// Get the value of the `IP_HDRINCL` option on this socket.
1759    ///
1760    /// For more information about this option, see [`set_header_included_v6`].
1761    ///
1762    /// [`set_header_included_v6`]: Socket::set_header_included_v6
1763    #[cfg(all(
1764        feature = "all",
1765        not(any(
1766            target_os = "redox",
1767            target_os = "espidf",
1768            target_os = "openbsd",
1769            target_os = "freebsd",
1770            target_os = "dragonfly",
1771            target_os = "netbsd",
1772            target_os = "wasi",
1773            target_os = "horizon"
1774        ))
1775    ))]
1776    pub fn header_included_v6(&self) -> io::Result<bool> {
1777        unsafe {
1778            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IP_HDRINCL)
1779                .map(|included| included != 0)
1780        }
1781    }
1782
1783    /// Set the value of the `IP_HDRINCL` option on this socket.
1784    ///
1785    /// If enabled, the user supplies an IP header in front of the user data.
1786    /// Valid only for [`SOCK_RAW`] sockets; see [raw(7)] for more information.
1787    /// When this flag is enabled, the values set by `IP_OPTIONS` are ignored.
1788    ///
1789    /// [`SOCK_RAW`]: Type::RAW
1790    /// [raw(7)]: https://man7.org/linux/man-pages/man7/raw.7.html
1791    #[cfg_attr(
1792        any(target_os = "fuchsia", target_os = "illumos", target_os = "solaris"),
1793        allow(rustdoc::broken_intra_doc_links)
1794    )]
1795    #[cfg(all(
1796        feature = "all",
1797        not(any(
1798            target_os = "redox",
1799            target_os = "espidf",
1800            target_os = "openbsd",
1801            target_os = "freebsd",
1802            target_os = "dragonfly",
1803            target_os = "netbsd",
1804            target_os = "wasi",
1805            target_os = "horizon"
1806        ))
1807    ))]
1808    pub fn set_header_included_v6(&self, included: bool) -> io::Result<()> {
1809        unsafe {
1810            setsockopt(
1811                self.as_raw(),
1812                sys::IPPROTO_IPV6,
1813                #[cfg(target_os = "linux")]
1814                sys::IPV6_HDRINCL,
1815                #[cfg(not(target_os = "linux"))]
1816                sys::IP_HDRINCL,
1817                included as c_int,
1818            )
1819        }
1820    }
1821
1822    /// Get the value of the `IPV6_TRANSPARENT` option on this socket.
1823    ///
1824    /// For more information about this option, see [`set_ip_transparent_v6`].
1825    ///
1826    /// [`set_ip_transparent_v6`]: Socket::set_ip_transparent_v6
1827    #[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
1828    pub fn ip_transparent_v6(&self) -> io::Result<bool> {
1829        unsafe {
1830            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, libc::IPV6_TRANSPARENT)
1831                .map(|transparent| transparent != 0)
1832        }
1833    }
1834
1835    /// Set the value of the `IPV6_TRANSPARENT` option on this socket.
1836    ///
1837    /// Setting this boolean option enables transparent proxying
1838    /// on this socket.  This socket option allows the calling
1839    /// application to bind to a nonlocal IP address and operate
1840    /// both as a client and a server with the foreign address as
1841    /// the local endpoint.  NOTE: this requires that routing be
1842    /// set up in a way that packets going to the foreign address
1843    /// are routed through the TProxy box (i.e., the system
1844    /// hosting the application that employs the IPV6_TRANSPARENT
1845    /// socket option).  Enabling this socket option requires
1846    /// superuser privileges (the `CAP_NET_ADMIN` capability).
1847    ///
1848    /// TProxy redirection with the iptables TPROXY target also
1849    /// requires that this option be set on the redirected socket.
1850    #[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
1851    pub fn set_ip_transparent_v6(&self, transparent: bool) -> io::Result<()> {
1852        unsafe {
1853            setsockopt(
1854                self.as_raw(),
1855                sys::IPPROTO_IPV6,
1856                libc::IPV6_TRANSPARENT,
1857                transparent as c_int,
1858            )
1859        }
1860    }
1861
1862    /// Join a multicast group using `IPV6_ADD_MEMBERSHIP` option on this socket.
1863    ///
1864    /// Some OSs use `IPV6_JOIN_GROUP` for this option.
1865    ///
1866    /// This function specifies a new multicast group for this socket to join.
1867    /// The address must be a valid multicast address, and `interface` is the
1868    /// index of the interface to join/leave (or 0 to indicate any interface).
1869    #[cfg(not(target_os = "nto"))]
1870    pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
1871        let mreq = sys::Ipv6Mreq {
1872            ipv6mr_multiaddr: sys::to_in6_addr(multiaddr),
1873            // NOTE: some OSs use `c_int`, others use `c_uint`.
1874            ipv6mr_interface: interface as _,
1875        };
1876        unsafe {
1877            setsockopt(
1878                self.as_raw(),
1879                sys::IPPROTO_IPV6,
1880                sys::IPV6_ADD_MEMBERSHIP,
1881                mreq,
1882            )
1883        }
1884    }
1885
1886    /// Leave a multicast group using `IPV6_DROP_MEMBERSHIP` option on this socket.
1887    ///
1888    /// Some OSs use `IPV6_LEAVE_GROUP` for this option.
1889    ///
1890    /// For more information about this option, see [`join_multicast_v6`].
1891    ///
1892    /// [`join_multicast_v6`]: Socket::join_multicast_v6
1893    #[cfg(not(target_os = "nto"))]
1894    pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
1895        let mreq = sys::Ipv6Mreq {
1896            ipv6mr_multiaddr: sys::to_in6_addr(multiaddr),
1897            // NOTE: some OSs use `c_int`, others use `c_uint`.
1898            ipv6mr_interface: interface as _,
1899        };
1900        unsafe {
1901            setsockopt(
1902                self.as_raw(),
1903                sys::IPPROTO_IPV6,
1904                sys::IPV6_DROP_MEMBERSHIP,
1905                mreq,
1906            )
1907        }
1908    }
1909
1910    /// Get the value of the `IPV6_MULTICAST_HOPS` option for this socket
1911    ///
1912    /// For more information about this option, see [`set_multicast_hops_v6`].
1913    ///
1914    /// [`set_multicast_hops_v6`]: Socket::set_multicast_hops_v6
1915    #[cfg(not(target_os = "wasi"))]
1916    pub fn multicast_hops_v6(&self) -> io::Result<u32> {
1917        unsafe {
1918            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_MULTICAST_HOPS)
1919                .map(|hops| hops as u32)
1920        }
1921    }
1922
1923    /// Set the value of the `IPV6_MULTICAST_HOPS` option for this socket
1924    ///
1925    /// Indicates the number of "routers" multicast packets will transit for
1926    /// this socket. The default value is 1 which means that multicast packets
1927    /// don't leave the local network unless explicitly requested.
1928    #[cfg(not(target_os = "wasi"))]
1929    pub fn set_multicast_hops_v6(&self, hops: u32) -> io::Result<()> {
1930        unsafe {
1931            setsockopt(
1932                self.as_raw(),
1933                sys::IPPROTO_IPV6,
1934                sys::IPV6_MULTICAST_HOPS,
1935                hops as c_int,
1936            )
1937        }
1938    }
1939
1940    /// Get the value of the `IPV6_MULTICAST_ALL` option for this socket.
1941    ///
1942    /// For more information about this option, see [`set_multicast_all_v6`].
1943    ///
1944    /// [`set_multicast_all_v6`]: Socket::set_multicast_all_v6
1945    #[cfg(all(feature = "all", target_os = "linux"))]
1946    pub fn multicast_all_v6(&self) -> io::Result<bool> {
1947        unsafe {
1948            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, libc::IPV6_MULTICAST_ALL)
1949                .map(|all| all != 0)
1950        }
1951    }
1952
1953    /// Set the value of the `IPV6_MULTICAST_ALL` option for this socket.
1954    ///
1955    /// This option can be used to modify the delivery policy of
1956    /// multicast messages.  The argument is a boolean
1957    /// (defaults to true).  If set to true, the socket will receive
1958    /// messages from all the groups that have been joined
1959    /// globally on the whole system.  Otherwise, it will deliver
1960    /// messages only from the groups that have been explicitly
1961    /// joined (for example via the `IPV6_ADD_MEMBERSHIP` option) on
1962    /// this particular socket.
1963    #[cfg(all(feature = "all", target_os = "linux"))]
1964    pub fn set_multicast_all_v6(&self, all: bool) -> io::Result<()> {
1965        unsafe {
1966            setsockopt(
1967                self.as_raw(),
1968                sys::IPPROTO_IPV6,
1969                libc::IPV6_MULTICAST_ALL,
1970                all as c_int,
1971            )
1972        }
1973    }
1974
1975    /// Get the value of the `IPV6_MULTICAST_IF` option for this socket.
1976    ///
1977    /// For more information about this option, see [`set_multicast_if_v6`].
1978    ///
1979    /// [`set_multicast_if_v6`]: Socket::set_multicast_if_v6
1980    #[cfg(not(target_os = "wasi"))]
1981    pub fn multicast_if_v6(&self) -> io::Result<u32> {
1982        unsafe {
1983            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_MULTICAST_IF)
1984                .map(|interface| interface as u32)
1985        }
1986    }
1987
1988    /// Set the value of the `IPV6_MULTICAST_IF` option for this socket.
1989    ///
1990    /// Specifies the interface to use for routing multicast packets. Unlike
1991    /// ipv4, this is generally required in ipv6 contexts where network routing
1992    /// prefixes may overlap.
1993    #[cfg(not(target_os = "wasi"))]
1994    pub fn set_multicast_if_v6(&self, interface: u32) -> io::Result<()> {
1995        unsafe {
1996            setsockopt(
1997                self.as_raw(),
1998                sys::IPPROTO_IPV6,
1999                sys::IPV6_MULTICAST_IF,
2000                interface as c_int,
2001            )
2002        }
2003    }
2004
2005    /// Get the value of the `IPV6_MULTICAST_LOOP` option for this socket.
2006    ///
2007    /// For more information about this option, see [`set_multicast_loop_v6`].
2008    ///
2009    /// [`set_multicast_loop_v6`]: Socket::set_multicast_loop_v6
2010    pub fn multicast_loop_v6(&self) -> io::Result<bool> {
2011        unsafe {
2012            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_MULTICAST_LOOP)
2013                .map(|loop_v6| loop_v6 != 0)
2014        }
2015    }
2016
2017    /// Set the value of the `IPV6_MULTICAST_LOOP` option for this socket.
2018    ///
2019    /// Controls whether this socket sees the multicast packets it sends itself.
2020    /// Note that this may not have any affect on IPv4 sockets.
2021    pub fn set_multicast_loop_v6(&self, loop_v6: bool) -> io::Result<()> {
2022        unsafe {
2023            setsockopt(
2024                self.as_raw(),
2025                sys::IPPROTO_IPV6,
2026                sys::IPV6_MULTICAST_LOOP,
2027                loop_v6 as c_int,
2028            )
2029        }
2030    }
2031
2032    /// Get the value of the `IPV6_UNICAST_HOPS` option for this socket.
2033    ///
2034    /// Specifies the hop limit for ipv6 unicast packets
2035    pub fn unicast_hops_v6(&self) -> io::Result<u32> {
2036        unsafe {
2037            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_UNICAST_HOPS)
2038                .map(|hops| hops as u32)
2039        }
2040    }
2041
2042    /// Set the value for the `IPV6_UNICAST_HOPS` option on this socket.
2043    ///
2044    /// Specifies the hop limit for ipv6 unicast packets
2045    pub fn set_unicast_hops_v6(&self, hops: u32) -> io::Result<()> {
2046        unsafe {
2047            setsockopt(
2048                self.as_raw(),
2049                sys::IPPROTO_IPV6,
2050                sys::IPV6_UNICAST_HOPS,
2051                hops as c_int,
2052            )
2053        }
2054    }
2055
2056    /// Get the value of the `IPV6_V6ONLY` option for this socket.
2057    ///
2058    /// For more information about this option, see [`set_only_v6`].
2059    ///
2060    /// [`set_only_v6`]: Socket::set_only_v6
2061    pub fn only_v6(&self) -> io::Result<bool> {
2062        unsafe {
2063            getsockopt::<Bool>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_V6ONLY)
2064                .map(|only_v6| only_v6 != 0)
2065        }
2066    }
2067
2068    /// Set the value for the `IPV6_V6ONLY` option on this socket.
2069    ///
2070    /// If this is set to `true` then the socket is restricted to sending and
2071    /// receiving IPv6 packets only. In this case two IPv4 and IPv6 applications
2072    /// can bind the same port at the same time.
2073    ///
2074    /// If this is set to `false` then the socket can be used to send and
2075    /// receive packets from an IPv4-mapped IPv6 address.
2076    pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
2077        unsafe {
2078            setsockopt(
2079                self.as_raw(),
2080                sys::IPPROTO_IPV6,
2081                sys::IPV6_V6ONLY,
2082                only_v6 as c_int,
2083            )
2084        }
2085    }
2086
2087    /// Get the value of the `IPV6_RECVTCLASS` option for this socket.
2088    ///
2089    /// For more information about this option, see [`set_recv_tclass_v6`].
2090    ///
2091    /// [`set_recv_tclass_v6`]: Socket::set_recv_tclass_v6
2092    #[cfg(not(any(
2093        target_os = "dragonfly",
2094        target_os = "fuchsia",
2095        target_os = "illumos",
2096        target_os = "netbsd",
2097        target_os = "openbsd",
2098        target_os = "redox",
2099        target_os = "solaris",
2100        target_os = "haiku",
2101        target_os = "hurd",
2102        target_os = "espidf",
2103        target_os = "vita",
2104        target_os = "wasi",
2105        target_os = "horizon"
2106    )))]
2107    pub fn recv_tclass_v6(&self) -> io::Result<bool> {
2108        unsafe {
2109            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_RECVTCLASS)
2110                .map(|recv_tclass| recv_tclass > 0)
2111        }
2112    }
2113
2114    /// Set the value of the `IPV6_RECVTCLASS` option for this socket.
2115    ///
2116    /// If enabled, the `IPV6_TCLASS` ancillary message is passed with incoming
2117    /// packets. It contains a byte which specifies the traffic class field of
2118    /// the packet header.
2119    #[cfg(not(any(
2120        target_os = "dragonfly",
2121        target_os = "fuchsia",
2122        target_os = "illumos",
2123        target_os = "netbsd",
2124        target_os = "openbsd",
2125        target_os = "redox",
2126        target_os = "solaris",
2127        target_os = "haiku",
2128        target_os = "hurd",
2129        target_os = "espidf",
2130        target_os = "vita",
2131        target_os = "wasi",
2132        target_os = "horizon"
2133    )))]
2134    pub fn set_recv_tclass_v6(&self, recv_tclass: bool) -> io::Result<()> {
2135        unsafe {
2136            setsockopt(
2137                self.as_raw(),
2138                sys::IPPROTO_IPV6,
2139                sys::IPV6_RECVTCLASS,
2140                recv_tclass as c_int,
2141            )
2142        }
2143    }
2144
2145    /// Get the value of the `IPV6_RECVHOPLIMIT` option for this socket.
2146    ///
2147    /// For more information about this option, see [`set_recv_hoplimit_v6`].
2148    ///
2149    /// [`set_recv_hoplimit_v6`]: Socket::set_recv_hoplimit_v6
2150    #[cfg(all(
2151        feature = "all",
2152        not(any(
2153            windows,
2154            target_os = "dragonfly",
2155            target_os = "fuchsia",
2156            target_os = "illumos",
2157            target_os = "netbsd",
2158            target_os = "openbsd",
2159            target_os = "redox",
2160            target_os = "solaris",
2161            target_os = "haiku",
2162            target_os = "hurd",
2163            target_os = "espidf",
2164            target_os = "vita",
2165            target_os = "cygwin",
2166            target_os = "wasi",
2167            target_os = "horizon"
2168        ))
2169    ))]
2170    pub fn recv_hoplimit_v6(&self) -> io::Result<bool> {
2171        unsafe {
2172            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_RECVHOPLIMIT)
2173                .map(|recv_hoplimit| recv_hoplimit > 0)
2174        }
2175    }
2176    /// Set the value of the `IPV6_RECVHOPLIMIT` option for this socket.
2177    ///
2178    /// The received hop limit is returned as ancillary data by recvmsg()
2179    /// only if the application has enabled the IPV6_RECVHOPLIMIT socket
2180    /// option:
2181    #[cfg(all(
2182        feature = "all",
2183        not(any(
2184            windows,
2185            target_os = "dragonfly",
2186            target_os = "fuchsia",
2187            target_os = "illumos",
2188            target_os = "netbsd",
2189            target_os = "openbsd",
2190            target_os = "redox",
2191            target_os = "solaris",
2192            target_os = "haiku",
2193            target_os = "hurd",
2194            target_os = "espidf",
2195            target_os = "vita",
2196            target_os = "cygwin",
2197            target_os = "wasi",
2198            target_os = "horizon"
2199        ))
2200    ))]
2201    pub fn set_recv_hoplimit_v6(&self, recv_hoplimit: bool) -> io::Result<()> {
2202        unsafe {
2203            setsockopt(
2204                self.as_raw(),
2205                sys::IPPROTO_IPV6,
2206                sys::IPV6_RECVHOPLIMIT,
2207                recv_hoplimit as c_int,
2208            )
2209        }
2210    }
2211
2212    /// Get the value for the `IP6T_SO_ORIGINAL_DST` option on this socket.
2213    #[cfg(all(
2214        feature = "all",
2215        any(target_os = "android", target_os = "linux", target_os = "windows")
2216    ))]
2217    pub fn original_dst_v6(&self) -> io::Result<SockAddr> {
2218        sys::original_dst_v6(self.as_raw())
2219    }
2220}
2221
2222/// Socket options for TCP sockets, get/set using `IPPROTO_TCP`.
2223///
2224/// Additional documentation can be found in documentation of the OS.
2225/// * Linux: <https://man7.org/linux/man-pages/man7/tcp.7.html>
2226/// * Windows: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-tcp-socket-options>
2227impl Socket {
2228    /// Get the value of the `TCP_KEEPIDLE` option on this socket.
2229    ///
2230    /// This returns the value of `TCP_KEEPALIVE` on macOS and iOS and `TCP_KEEPIDLE` on all other
2231    /// supported Unix operating systems.
2232    #[cfg(all(
2233        feature = "all",
2234        not(any(
2235            windows,
2236            target_os = "haiku",
2237            target_os = "openbsd",
2238            target_os = "vita"
2239        ))
2240    ))]
2241    pub fn tcp_keepalive_time(&self) -> io::Result<Duration> {
2242        sys::tcp_keepalive_time(self.as_raw())
2243    }
2244
2245    /// Get the value of the `TCP_KEEPINTVL` option on this socket.
2246    ///
2247    /// For more information about this option, see [`set_tcp_keepalive`].
2248    ///
2249    /// [`set_tcp_keepalive`]: Socket::set_tcp_keepalive
2250    #[cfg(all(
2251        feature = "all",
2252        any(
2253            target_os = "android",
2254            target_os = "dragonfly",
2255            target_os = "freebsd",
2256            target_os = "fuchsia",
2257            target_os = "illumos",
2258            target_os = "ios",
2259            target_os = "visionos",
2260            target_os = "linux",
2261            target_os = "macos",
2262            target_os = "netbsd",
2263            target_os = "tvos",
2264            target_os = "watchos",
2265            target_os = "cygwin",
2266            all(target_os = "wasi", not(target_env = "p1")),
2267        )
2268    ))]
2269    pub fn tcp_keepalive_interval(&self) -> io::Result<Duration> {
2270        unsafe {
2271            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_TCP, sys::TCP_KEEPINTVL)
2272                .map(|secs| Duration::from_secs(secs as u64))
2273        }
2274    }
2275
2276    /// Get the value of the `TCP_KEEPCNT` option on this socket.
2277    ///
2278    /// For more information about this option, see [`set_tcp_keepalive`].
2279    ///
2280    /// [`set_tcp_keepalive`]: Socket::set_tcp_keepalive
2281    #[cfg(all(
2282        feature = "all",
2283        any(
2284            target_os = "android",
2285            target_os = "dragonfly",
2286            target_os = "freebsd",
2287            target_os = "fuchsia",
2288            target_os = "illumos",
2289            target_os = "ios",
2290            target_os = "visionos",
2291            target_os = "linux",
2292            target_os = "macos",
2293            target_os = "netbsd",
2294            target_os = "tvos",
2295            target_os = "watchos",
2296            target_os = "cygwin",
2297            target_os = "windows",
2298            all(target_os = "wasi", not(target_env = "p1")),
2299        )
2300    ))]
2301    pub fn tcp_keepalive_retries(&self) -> io::Result<u32> {
2302        unsafe {
2303            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_TCP, sys::TCP_KEEPCNT)
2304                .map(|retries| retries as u32)
2305        }
2306    }
2307
2308    /// Set parameters configuring TCP keepalive probes for this socket.
2309    ///
2310    /// The supported parameters depend on the operating system, and are
2311    /// configured using the [`TcpKeepalive`] struct. At a minimum, all systems
2312    /// support configuring the [keepalive time]: the time after which the OS
2313    /// will start sending keepalive messages on an idle connection.
2314    ///
2315    /// [keepalive time]: TcpKeepalive::with_time
2316    ///
2317    /// # Notes
2318    ///
2319    /// * This will enable `SO_KEEPALIVE` on this socket, if it is not already
2320    ///   enabled.
2321    /// * On some platforms, such as Windows, any keepalive parameters *not*
2322    ///   configured by the `TcpKeepalive` struct passed to this function may be
2323    ///   overwritten with their default values. Therefore, this function should
2324    ///   either only be called once per socket, or the same parameters should
2325    ///   be passed every time it is called.
2326    ///
2327    /// # Examples
2328    ///
2329    /// ```
2330    /// use std::time::Duration;
2331    ///
2332    /// use socket2::{Socket, TcpKeepalive, Domain, Type};
2333    ///
2334    /// # fn main() -> std::io::Result<()> {
2335    /// let socket = Socket::new(Domain::IPV4, Type::STREAM, None)?;
2336    /// let keepalive = TcpKeepalive::new()
2337    ///     .with_time(Duration::from_secs(4));
2338    ///     // Depending on the target operating system, we may also be able to
2339    ///     // configure the keepalive probe interval and/or the number of
2340    ///     // retries here as well.
2341    ///
2342    /// socket.set_tcp_keepalive(&keepalive)?;
2343    /// # Ok(()) }
2344    /// ```
2345    ///
2346    pub fn set_tcp_keepalive(&self, params: &TcpKeepalive) -> io::Result<()> {
2347        self.set_keepalive(true)?;
2348        sys::set_tcp_keepalive(self.as_raw(), params)
2349    }
2350
2351    /// Get the value of the `TCP_NODELAY` option on this socket.
2352    ///
2353    /// For more information about this option, see [`set_tcp_nodelay`].
2354    ///
2355    /// [`set_tcp_nodelay`]: Socket::set_tcp_nodelay
2356    pub fn tcp_nodelay(&self) -> io::Result<bool> {
2357        unsafe {
2358            getsockopt::<Bool>(self.as_raw(), sys::IPPROTO_TCP, sys::TCP_NODELAY)
2359                .map(|nodelay| nodelay != 0)
2360        }
2361    }
2362
2363    /// Set the value of the `TCP_NODELAY` option on this socket.
2364    ///
2365    /// If set, this option disables the Nagle algorithm. This means that
2366    /// segments are always sent as soon as possible, even if there is only a
2367    /// small amount of data. When not set, data is buffered until there is a
2368    /// sufficient amount to send out, thereby avoiding the frequent sending of
2369    /// small packets.
2370    pub fn set_tcp_nodelay(&self, nodelay: bool) -> io::Result<()> {
2371        unsafe {
2372            setsockopt(
2373                self.as_raw(),
2374                sys::IPPROTO_TCP,
2375                sys::TCP_NODELAY,
2376                nodelay as c_int,
2377            )
2378        }
2379    }
2380
2381    /// On Windows this invokes the `SIO_TCP_SET_ACK_FREQUENCY` IOCTL which
2382    /// configures the number of TCP segments that must be received before
2383    /// the delayed ACK timer is ignored.
2384    #[cfg(all(feature = "all", windows))]
2385    pub fn set_tcp_ack_frequency(&self, frequency: u8) -> io::Result<()> {
2386        sys::set_tcp_ack_frequency(self.as_raw(), frequency)
2387    }
2388}
2389
2390impl Read for Socket {
2391    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
2392        // Safety: the `recv` implementation promises not to write uninitialised
2393        // bytes to the `buf`fer, so this casting is safe.
2394        let buf = unsafe { &mut *(buf as *mut [u8] as *mut [MaybeUninit<u8>]) };
2395        self.recv(buf)
2396    }
2397
2398    #[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
2399    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
2400        // Safety: both `IoSliceMut` and `MaybeUninitSlice` promise to have the
2401        // same layout, that of `iovec`/`WSABUF`. Furthermore, `recv_vectored`
2402        // promises to not write uninitialised bytes to the `bufs` and pass it
2403        // directly to the `recvmsg` system call, so this is safe.
2404        let bufs = unsafe { &mut *(bufs as *mut [IoSliceMut<'_>] as *mut [MaybeUninitSlice<'_>]) };
2405        self.recv_vectored(bufs).map(|(n, _)| n)
2406    }
2407}
2408
2409impl<'a> Read for &'a Socket {
2410    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
2411        // Safety: see other `Read::read` impl.
2412        let buf = unsafe { &mut *(buf as *mut [u8] as *mut [MaybeUninit<u8>]) };
2413        self.recv(buf)
2414    }
2415
2416    #[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
2417    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
2418        // Safety: see other `Read::read` impl.
2419        let bufs = unsafe { &mut *(bufs as *mut [IoSliceMut<'_>] as *mut [MaybeUninitSlice<'_>]) };
2420        self.recv_vectored(bufs).map(|(n, _)| n)
2421    }
2422}
2423
2424impl Write for Socket {
2425    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
2426        self.send(buf)
2427    }
2428
2429    #[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
2430    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
2431        self.send_vectored(bufs)
2432    }
2433
2434    fn flush(&mut self) -> io::Result<()> {
2435        Ok(())
2436    }
2437}
2438
2439impl<'a> Write for &'a Socket {
2440    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
2441        self.send(buf)
2442    }
2443
2444    #[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
2445    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
2446        self.send_vectored(bufs)
2447    }
2448
2449    fn flush(&mut self) -> io::Result<()> {
2450        Ok(())
2451    }
2452}
2453
2454impl fmt::Debug for Socket {
2455    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2456        f.debug_struct("Socket")
2457            .field("raw", &self.as_raw())
2458            .field("local_addr", &self.local_addr().ok())
2459            .field("peer_addr", &self.peer_addr().ok())
2460            .finish()
2461    }
2462}
2463
2464from!(net::TcpStream, Socket);
2465from!(net::TcpListener, Socket);
2466from!(net::UdpSocket, Socket);
2467from!(Socket, net::TcpStream);
2468from!(Socket, net::TcpListener);
2469from!(Socket, net::UdpSocket);