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(any(target_os = "nto", target_os = "nuttx")))]
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 = "nuttx",
1218            target_os = "wasi",
1219            target_os = "horizon"
1220        ))
1221    ))]
1222    pub fn header_included_v4(&self) -> io::Result<bool> {
1223        unsafe {
1224            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_HDRINCL)
1225                .map(|included| included != 0)
1226        }
1227    }
1228
1229    /// Set the value of the `IP_HDRINCL` option on this socket.
1230    ///
1231    /// If enabled, the user supplies an IP header in front of the user data.
1232    /// Valid only for [`SOCK_RAW`] sockets; see [raw(7)] for more information.
1233    /// When this flag is enabled, the values set by `IP_OPTIONS`, [`IP_TTL`],
1234    /// and [`IP_TOS`] are ignored.
1235    ///
1236    /// [`SOCK_RAW`]: Type::RAW
1237    /// [raw(7)]: https://man7.org/linux/man-pages/man7/raw.7.html
1238    /// [`IP_TTL`]: Socket::set_ttl_v4
1239    /// [`IP_TOS`]: Socket::set_tos_v4
1240    #[cfg_attr(
1241        any(target_os = "fuchsia", target_os = "illumos", target_os = "solaris"),
1242        allow(rustdoc::broken_intra_doc_links)
1243    )]
1244    #[cfg(all(
1245        feature = "all",
1246        not(any(
1247            target_os = "redox",
1248            target_os = "espidf",
1249            target_os = "nuttx",
1250            target_os = "wasi",
1251            target_os = "horizon"
1252        ))
1253    ))]
1254    pub fn set_header_included_v4(&self, included: bool) -> io::Result<()> {
1255        unsafe {
1256            setsockopt(
1257                self.as_raw(),
1258                sys::IPPROTO_IP,
1259                sys::IP_HDRINCL,
1260                included as c_int,
1261            )
1262        }
1263    }
1264
1265    /// Get the value of the `IP_TRANSPARENT` option on this socket.
1266    ///
1267    /// For more information about this option, see [`set_ip_transparent_v4`].
1268    ///
1269    /// [`set_ip_transparent_v4`]: Socket::set_ip_transparent_v4
1270    #[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
1271    pub fn ip_transparent_v4(&self) -> io::Result<bool> {
1272        unsafe {
1273            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, libc::IP_TRANSPARENT)
1274                .map(|transparent| transparent != 0)
1275        }
1276    }
1277
1278    /// Set the value of the `IP_TRANSPARENT` option on this socket.
1279    ///
1280    /// Setting this boolean option enables transparent proxying
1281    /// on this socket.  This socket option allows the calling
1282    /// application to bind to a nonlocal IP address and operate
1283    /// both as a client and a server with the foreign address as
1284    /// the local endpoint.  NOTE: this requires that routing be
1285    /// set up in a way that packets going to the foreign address
1286    /// are routed through the TProxy box (i.e., the system
1287    /// hosting the application that employs the IP_TRANSPARENT
1288    /// socket option).  Enabling this socket option requires
1289    /// superuser privileges (the `CAP_NET_ADMIN` capability).
1290    ///
1291    /// TProxy redirection with the iptables TPROXY target also
1292    /// requires that this option be set on the redirected socket.
1293    #[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
1294    pub fn set_ip_transparent_v4(&self, transparent: bool) -> io::Result<()> {
1295        unsafe {
1296            setsockopt(
1297                self.as_raw(),
1298                sys::IPPROTO_IP,
1299                libc::IP_TRANSPARENT,
1300                transparent as c_int,
1301            )
1302        }
1303    }
1304
1305    /// Join a multicast group using `IP_ADD_MEMBERSHIP` option on this socket.
1306    ///
1307    /// This function specifies a new multicast group for this socket to join.
1308    /// The address must be a valid multicast address, and `interface` is the
1309    /// address of the local interface with which the system should join the
1310    /// multicast group. If it's [`Ipv4Addr::UNSPECIFIED`] (`INADDR_ANY`) then
1311    /// an appropriate interface is chosen by the system.
1312    pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
1313        let mreq = sys::IpMreq {
1314            imr_multiaddr: sys::to_in_addr(multiaddr),
1315            imr_interface: sys::to_in_addr(interface),
1316        };
1317        unsafe { setsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_ADD_MEMBERSHIP, mreq) }
1318    }
1319
1320    /// Leave a multicast group using `IP_DROP_MEMBERSHIP` option on this socket.
1321    ///
1322    /// For more information about this option, see [`join_multicast_v4`].
1323    ///
1324    /// [`join_multicast_v4`]: Socket::join_multicast_v4
1325    pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
1326        let mreq = sys::IpMreq {
1327            imr_multiaddr: sys::to_in_addr(multiaddr),
1328            imr_interface: sys::to_in_addr(interface),
1329        };
1330        unsafe {
1331            setsockopt(
1332                self.as_raw(),
1333                sys::IPPROTO_IP,
1334                sys::IP_DROP_MEMBERSHIP,
1335                mreq,
1336            )
1337        }
1338    }
1339
1340    /// Join a multicast group using `IP_ADD_MEMBERSHIP` option on this socket.
1341    ///
1342    /// This function specifies a new multicast group for this socket to join.
1343    /// The address must be a valid multicast address, and `interface` specifies
1344    /// the local interface with which the system should join the multicast
1345    /// group. See [`InterfaceIndexOrAddress`].
1346    #[cfg(not(any(
1347        target_os = "aix",
1348        target_os = "haiku",
1349        target_os = "illumos",
1350        target_os = "netbsd",
1351        target_os = "openbsd",
1352        target_os = "redox",
1353        target_os = "solaris",
1354        target_os = "nto",
1355        target_os = "espidf",
1356        target_os = "vita",
1357        target_os = "cygwin",
1358        target_os = "wasi",
1359        target_os = "horizon"
1360    )))]
1361    pub fn join_multicast_v4_n(
1362        &self,
1363        multiaddr: &Ipv4Addr,
1364        interface: &InterfaceIndexOrAddress,
1365    ) -> io::Result<()> {
1366        let mreqn = sys::to_mreqn(multiaddr, interface);
1367        unsafe {
1368            setsockopt(
1369                self.as_raw(),
1370                sys::IPPROTO_IP,
1371                sys::IP_ADD_MEMBERSHIP,
1372                mreqn,
1373            )
1374        }
1375    }
1376
1377    /// Leave a multicast group using `IP_DROP_MEMBERSHIP` option on this socket.
1378    ///
1379    /// For more information about this option, see [`join_multicast_v4_n`].
1380    ///
1381    /// [`join_multicast_v4_n`]: Socket::join_multicast_v4_n
1382    #[cfg(not(any(
1383        target_os = "aix",
1384        target_os = "haiku",
1385        target_os = "illumos",
1386        target_os = "netbsd",
1387        target_os = "openbsd",
1388        target_os = "redox",
1389        target_os = "solaris",
1390        target_os = "nto",
1391        target_os = "espidf",
1392        target_os = "vita",
1393        target_os = "cygwin",
1394        target_os = "wasi",
1395        target_os = "horizon"
1396    )))]
1397    pub fn leave_multicast_v4_n(
1398        &self,
1399        multiaddr: &Ipv4Addr,
1400        interface: &InterfaceIndexOrAddress,
1401    ) -> io::Result<()> {
1402        let mreqn = sys::to_mreqn(multiaddr, interface);
1403        unsafe {
1404            setsockopt(
1405                self.as_raw(),
1406                sys::IPPROTO_IP,
1407                sys::IP_DROP_MEMBERSHIP,
1408                mreqn,
1409            )
1410        }
1411    }
1412
1413    /// Join a multicast SSM channel using `IP_ADD_SOURCE_MEMBERSHIP` option on this socket.
1414    ///
1415    /// This function specifies a new multicast channel for this socket to join.
1416    /// The group must be a valid SSM group address, the source must be the address of the sender
1417    /// and `interface` is the address of the local interface with which the system should join the
1418    /// multicast group. If it's [`Ipv4Addr::UNSPECIFIED`] (`INADDR_ANY`) then
1419    /// an appropriate interface is chosen by the system.
1420    #[cfg(not(any(
1421        target_os = "dragonfly",
1422        target_os = "haiku",
1423        target_os = "hurd",
1424        target_os = "netbsd",
1425        target_os = "openbsd",
1426        target_os = "redox",
1427        target_os = "fuchsia",
1428        target_os = "nto",
1429        target_os = "espidf",
1430        target_os = "vita",
1431        target_os = "wasi",
1432        target_os = "horizon"
1433    )))]
1434    pub fn join_ssm_v4(
1435        &self,
1436        source: &Ipv4Addr,
1437        group: &Ipv4Addr,
1438        interface: &Ipv4Addr,
1439    ) -> io::Result<()> {
1440        let mreqs = sys::IpMreqSource {
1441            imr_multiaddr: sys::to_in_addr(group),
1442            imr_interface: sys::to_in_addr(interface),
1443            imr_sourceaddr: sys::to_in_addr(source),
1444        };
1445        unsafe {
1446            setsockopt(
1447                self.as_raw(),
1448                sys::IPPROTO_IP,
1449                sys::IP_ADD_SOURCE_MEMBERSHIP,
1450                mreqs,
1451            )
1452        }
1453    }
1454
1455    /// Leave a multicast group using `IP_DROP_SOURCE_MEMBERSHIP` option on this socket.
1456    ///
1457    /// For more information about this option, see [`join_ssm_v4`].
1458    ///
1459    /// [`join_ssm_v4`]: Socket::join_ssm_v4
1460    #[cfg(not(any(
1461        target_os = "dragonfly",
1462        target_os = "haiku",
1463        target_os = "hurd",
1464        target_os = "netbsd",
1465        target_os = "openbsd",
1466        target_os = "redox",
1467        target_os = "fuchsia",
1468        target_os = "nto",
1469        target_os = "espidf",
1470        target_os = "vita",
1471        target_os = "wasi",
1472        target_os = "horizon"
1473    )))]
1474    pub fn leave_ssm_v4(
1475        &self,
1476        source: &Ipv4Addr,
1477        group: &Ipv4Addr,
1478        interface: &Ipv4Addr,
1479    ) -> io::Result<()> {
1480        let mreqs = sys::IpMreqSource {
1481            imr_multiaddr: sys::to_in_addr(group),
1482            imr_interface: sys::to_in_addr(interface),
1483            imr_sourceaddr: sys::to_in_addr(source),
1484        };
1485        unsafe {
1486            setsockopt(
1487                self.as_raw(),
1488                sys::IPPROTO_IP,
1489                sys::IP_DROP_SOURCE_MEMBERSHIP,
1490                mreqs,
1491            )
1492        }
1493    }
1494
1495    /// Get the value of the `IP_MULTICAST_ALL` option for this socket.
1496    ///
1497    /// For more information about this option, see [`set_multicast_all_v4`].
1498    ///
1499    /// [`set_multicast_all_v4`]: Socket::set_multicast_all_v4
1500    #[cfg(all(feature = "all", target_os = "linux"))]
1501    pub fn multicast_all_v4(&self) -> io::Result<bool> {
1502        unsafe {
1503            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, libc::IP_MULTICAST_ALL)
1504                .map(|all| all != 0)
1505        }
1506    }
1507
1508    /// Set the value of the `IP_MULTICAST_ALL` option for this socket.
1509    ///
1510    /// This option can be used to modify the delivery policy of
1511    /// multicast messages.  The argument is a boolean
1512    /// (defaults to true).  If set to true, the socket will receive
1513    /// messages from all the groups that have been joined
1514    /// globally on the whole system.  Otherwise, it will deliver
1515    /// messages only from the groups that have been explicitly
1516    /// joined (for example via the `IP_ADD_MEMBERSHIP` option) on
1517    /// this particular socket.
1518    #[cfg(all(feature = "all", target_os = "linux"))]
1519    pub fn set_multicast_all_v4(&self, all: bool) -> io::Result<()> {
1520        unsafe {
1521            setsockopt(
1522                self.as_raw(),
1523                sys::IPPROTO_IP,
1524                libc::IP_MULTICAST_ALL,
1525                all as c_int,
1526            )
1527        }
1528    }
1529
1530    /// Get the value of the `IP_MULTICAST_IF` option for this socket.
1531    ///
1532    /// For more information about this option, see [`set_multicast_if_v4`].
1533    ///
1534    /// [`set_multicast_if_v4`]: Socket::set_multicast_if_v4
1535    #[cfg(not(target_os = "wasi"))]
1536    pub fn multicast_if_v4(&self) -> io::Result<Ipv4Addr> {
1537        unsafe {
1538            getsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_MULTICAST_IF).map(sys::from_in_addr)
1539        }
1540    }
1541
1542    /// Set the value of the `IP_MULTICAST_IF` option for this socket.
1543    ///
1544    /// Specifies the interface to use for routing multicast packets.
1545    #[cfg(not(target_os = "wasi"))]
1546    pub fn set_multicast_if_v4(&self, interface: &Ipv4Addr) -> io::Result<()> {
1547        let interface = sys::to_in_addr(interface);
1548        unsafe {
1549            setsockopt(
1550                self.as_raw(),
1551                sys::IPPROTO_IP,
1552                sys::IP_MULTICAST_IF,
1553                interface,
1554            )
1555        }
1556    }
1557
1558    /// Get the value of the `IP_MULTICAST_LOOP` option for this socket.
1559    ///
1560    /// For more information about this option, see [`set_multicast_loop_v4`].
1561    ///
1562    /// [`set_multicast_loop_v4`]: Socket::set_multicast_loop_v4
1563    pub fn multicast_loop_v4(&self) -> io::Result<bool> {
1564        unsafe {
1565            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_MULTICAST_LOOP)
1566                .map(|loop_v4| loop_v4 != 0)
1567        }
1568    }
1569
1570    /// Set the value of the `IP_MULTICAST_LOOP` option for this socket.
1571    ///
1572    /// If enabled, multicast packets will be looped back to the local socket.
1573    /// Note that this may not have any affect on IPv6 sockets.
1574    pub fn set_multicast_loop_v4(&self, loop_v4: bool) -> io::Result<()> {
1575        unsafe {
1576            setsockopt(
1577                self.as_raw(),
1578                sys::IPPROTO_IP,
1579                sys::IP_MULTICAST_LOOP,
1580                loop_v4 as c_int,
1581            )
1582        }
1583    }
1584
1585    /// Get the value of the `IP_MULTICAST_TTL` option for this socket.
1586    ///
1587    /// For more information about this option, see [`set_multicast_ttl_v4`].
1588    ///
1589    /// [`set_multicast_ttl_v4`]: Socket::set_multicast_ttl_v4
1590    pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
1591        unsafe {
1592            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_MULTICAST_TTL)
1593                .map(|ttl| ttl as u32)
1594        }
1595    }
1596
1597    /// Set the value of the `IP_MULTICAST_TTL` option for this socket.
1598    ///
1599    /// Indicates the time-to-live value of outgoing multicast packets for
1600    /// this socket. The default value is 1 which means that multicast packets
1601    /// don't leave the local network unless explicitly requested.
1602    ///
1603    /// Note that this may not have any affect on IPv6 sockets.
1604    pub fn set_multicast_ttl_v4(&self, ttl: u32) -> io::Result<()> {
1605        unsafe {
1606            setsockopt(
1607                self.as_raw(),
1608                sys::IPPROTO_IP,
1609                sys::IP_MULTICAST_TTL,
1610                ttl as c_int,
1611            )
1612        }
1613    }
1614
1615    /// Get the value of the `IP_TTL` option for this socket.
1616    ///
1617    /// For more information about this option, see [`set_ttl_v4`].
1618    ///
1619    /// [`set_ttl_v4`]: Socket::set_ttl_v4
1620    pub fn ttl_v4(&self) -> io::Result<u32> {
1621        unsafe {
1622            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_TTL).map(|ttl| ttl as u32)
1623        }
1624    }
1625
1626    /// Set the value of the `IP_TTL` option for this socket.
1627    ///
1628    /// This value sets the time-to-live field that is used in every packet sent
1629    /// from this socket.
1630    pub fn set_ttl_v4(&self, ttl: u32) -> io::Result<()> {
1631        unsafe { setsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_TTL, ttl as c_int) }
1632    }
1633
1634    /// Set the value of the `IP_TOS` option for this socket.
1635    ///
1636    /// This value sets the type-of-service field that is used in every packet
1637    /// sent from this socket.
1638    ///
1639    /// NOTE: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options>
1640    /// documents that not all versions of windows support `IP_TOS`.
1641    #[cfg(not(any(
1642        target_os = "fuchsia",
1643        target_os = "redox",
1644        target_os = "solaris",
1645        target_os = "haiku",
1646        target_os = "wasi",
1647    )))]
1648    pub fn set_tos_v4(&self, tos: u32) -> io::Result<()> {
1649        unsafe { setsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_TOS, tos as c_int) }
1650    }
1651
1652    /// Get the value of the `IP_TOS` option for this socket.
1653    ///
1654    /// For more information about this option, see [`set_tos_v4`].
1655    ///
1656    /// NOTE: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options>
1657    /// documents that not all versions of windows support `IP_TOS`.
1658    ///
1659    /// [`set_tos_v4`]: Socket::set_tos_v4
1660    #[cfg(not(any(
1661        target_os = "fuchsia",
1662        target_os = "redox",
1663        target_os = "solaris",
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 = "nuttx",
1692        target_os = "vita",
1693        target_os = "cygwin",
1694        target_os = "wasi",
1695        target_os = "horizon"
1696    )))]
1697    pub fn set_recv_tos_v4(&self, recv_tos: bool) -> io::Result<()> {
1698        unsafe {
1699            setsockopt(
1700                self.as_raw(),
1701                sys::IPPROTO_IP,
1702                sys::IP_RECVTOS,
1703                recv_tos as c_int,
1704            )
1705        }
1706    }
1707
1708    /// Get the value of the `IP_RECVTOS` option for this socket.
1709    ///
1710    /// For more information about this option, see [`set_recv_tos_v4`].
1711    ///
1712    /// [`set_recv_tos_v4`]: Socket::set_recv_tos_v4
1713    #[cfg(not(any(
1714        target_os = "aix",
1715        target_os = "dragonfly",
1716        target_os = "fuchsia",
1717        target_os = "hurd",
1718        target_os = "illumos",
1719        target_os = "netbsd",
1720        target_os = "openbsd",
1721        target_os = "redox",
1722        target_os = "solaris",
1723        target_os = "haiku",
1724        target_os = "nto",
1725        target_os = "espidf",
1726        target_os = "nuttx",
1727        target_os = "vita",
1728        target_os = "cygwin",
1729        target_os = "wasi",
1730        target_os = "horizon"
1731    )))]
1732    pub fn recv_tos_v4(&self) -> io::Result<bool> {
1733        unsafe {
1734            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_RECVTOS)
1735                .map(|recv_tos| recv_tos > 0)
1736        }
1737    }
1738
1739    /// Get the value for the `SO_ORIGINAL_DST` option on this socket.
1740    #[cfg(all(
1741        feature = "all",
1742        any(
1743            target_os = "android",
1744            target_os = "fuchsia",
1745            target_os = "linux",
1746            target_os = "windows",
1747        )
1748    ))]
1749    pub fn original_dst_v4(&self) -> io::Result<SockAddr> {
1750        sys::original_dst_v4(self.as_raw())
1751    }
1752}
1753
1754/// Socket options for IPv6 sockets, get/set using `IPPROTO_IPV6` or `SOL_IPV6`.
1755///
1756/// Additional documentation can be found in documentation of the OS.
1757/// * Linux: <https://man7.org/linux/man-pages/man7/ipv6.7.html>
1758/// * Windows: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ipv6-socket-options>
1759impl Socket {
1760    /// Get the value of the `IP_HDRINCL` option on this socket.
1761    ///
1762    /// For more information about this option, see [`set_header_included_v6`].
1763    ///
1764    /// [`set_header_included_v6`]: Socket::set_header_included_v6
1765    #[cfg(all(
1766        feature = "all",
1767        not(any(
1768            target_os = "redox",
1769            target_os = "espidf",
1770            target_os = "nuttx",
1771            target_os = "openbsd",
1772            target_os = "freebsd",
1773            target_os = "dragonfly",
1774            target_os = "netbsd",
1775            target_os = "wasi",
1776            target_os = "horizon"
1777        ))
1778    ))]
1779    pub fn header_included_v6(&self) -> io::Result<bool> {
1780        unsafe {
1781            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IP_HDRINCL)
1782                .map(|included| included != 0)
1783        }
1784    }
1785
1786    /// Set the value of the `IP_HDRINCL` option on this socket.
1787    ///
1788    /// If enabled, the user supplies an IP header in front of the user data.
1789    /// Valid only for [`SOCK_RAW`] sockets; see [raw(7)] for more information.
1790    /// When this flag is enabled, the values set by `IP_OPTIONS` are ignored.
1791    ///
1792    /// [`SOCK_RAW`]: Type::RAW
1793    /// [raw(7)]: https://man7.org/linux/man-pages/man7/raw.7.html
1794    #[cfg_attr(
1795        any(target_os = "fuchsia", target_os = "illumos", target_os = "solaris"),
1796        allow(rustdoc::broken_intra_doc_links)
1797    )]
1798    #[cfg(all(
1799        feature = "all",
1800        not(any(
1801            target_os = "redox",
1802            target_os = "espidf",
1803            target_os = "nuttx",
1804            target_os = "openbsd",
1805            target_os = "freebsd",
1806            target_os = "dragonfly",
1807            target_os = "netbsd",
1808            target_os = "wasi",
1809            target_os = "horizon"
1810        ))
1811    ))]
1812    pub fn set_header_included_v6(&self, included: bool) -> io::Result<()> {
1813        unsafe {
1814            setsockopt(
1815                self.as_raw(),
1816                sys::IPPROTO_IPV6,
1817                #[cfg(target_os = "linux")]
1818                sys::IPV6_HDRINCL,
1819                #[cfg(not(target_os = "linux"))]
1820                sys::IP_HDRINCL,
1821                included as c_int,
1822            )
1823        }
1824    }
1825
1826    /// Get the value of the `IPV6_TRANSPARENT` option on this socket.
1827    ///
1828    /// For more information about this option, see [`set_ip_transparent_v6`].
1829    ///
1830    /// [`set_ip_transparent_v6`]: Socket::set_ip_transparent_v6
1831    #[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
1832    pub fn ip_transparent_v6(&self) -> io::Result<bool> {
1833        unsafe {
1834            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, libc::IPV6_TRANSPARENT)
1835                .map(|transparent| transparent != 0)
1836        }
1837    }
1838
1839    /// Set the value of the `IPV6_TRANSPARENT` option on this socket.
1840    ///
1841    /// Setting this boolean option enables transparent proxying
1842    /// on this socket.  This socket option allows the calling
1843    /// application to bind to a nonlocal IP address and operate
1844    /// both as a client and a server with the foreign address as
1845    /// the local endpoint.  NOTE: this requires that routing be
1846    /// set up in a way that packets going to the foreign address
1847    /// are routed through the TProxy box (i.e., the system
1848    /// hosting the application that employs the IPV6_TRANSPARENT
1849    /// socket option).  Enabling this socket option requires
1850    /// superuser privileges (the `CAP_NET_ADMIN` capability).
1851    ///
1852    /// TProxy redirection with the iptables TPROXY target also
1853    /// requires that this option be set on the redirected socket.
1854    #[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))]
1855    pub fn set_ip_transparent_v6(&self, transparent: bool) -> io::Result<()> {
1856        unsafe {
1857            setsockopt(
1858                self.as_raw(),
1859                sys::IPPROTO_IPV6,
1860                libc::IPV6_TRANSPARENT,
1861                transparent as c_int,
1862            )
1863        }
1864    }
1865
1866    /// Join a multicast group using `IPV6_ADD_MEMBERSHIP` option on this socket.
1867    ///
1868    /// Some OSs use `IPV6_JOIN_GROUP` for this option.
1869    ///
1870    /// This function specifies a new multicast group for this socket to join.
1871    /// The address must be a valid multicast address, and `interface` is the
1872    /// index of the interface to join/leave (or 0 to indicate any interface).
1873    #[cfg(not(any(target_os = "nto", target_os = "nuttx")))]
1874    pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
1875        let mreq = sys::Ipv6Mreq {
1876            ipv6mr_multiaddr: sys::to_in6_addr(multiaddr),
1877            // NOTE: some OSs use `c_int`, others use `c_uint`.
1878            ipv6mr_interface: interface as _,
1879        };
1880        unsafe {
1881            setsockopt(
1882                self.as_raw(),
1883                sys::IPPROTO_IPV6,
1884                sys::IPV6_ADD_MEMBERSHIP,
1885                mreq,
1886            )
1887        }
1888    }
1889
1890    /// Leave a multicast group using `IPV6_DROP_MEMBERSHIP` option on this socket.
1891    ///
1892    /// Some OSs use `IPV6_LEAVE_GROUP` for this option.
1893    ///
1894    /// For more information about this option, see [`join_multicast_v6`].
1895    ///
1896    /// [`join_multicast_v6`]: Socket::join_multicast_v6
1897    #[cfg(not(any(target_os = "nto", target_os = "nuttx")))]
1898    pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
1899        let mreq = sys::Ipv6Mreq {
1900            ipv6mr_multiaddr: sys::to_in6_addr(multiaddr),
1901            // NOTE: some OSs use `c_int`, others use `c_uint`.
1902            ipv6mr_interface: interface as _,
1903        };
1904        unsafe {
1905            setsockopt(
1906                self.as_raw(),
1907                sys::IPPROTO_IPV6,
1908                sys::IPV6_DROP_MEMBERSHIP,
1909                mreq,
1910            )
1911        }
1912    }
1913
1914    /// Get the value of the `IPV6_MULTICAST_HOPS` option for this socket
1915    ///
1916    /// For more information about this option, see [`set_multicast_hops_v6`].
1917    ///
1918    /// [`set_multicast_hops_v6`]: Socket::set_multicast_hops_v6
1919    #[cfg(not(target_os = "wasi"))]
1920    pub fn multicast_hops_v6(&self) -> io::Result<u32> {
1921        unsafe {
1922            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_MULTICAST_HOPS)
1923                .map(|hops| hops as u32)
1924        }
1925    }
1926
1927    /// Set the value of the `IPV6_MULTICAST_HOPS` option for this socket
1928    ///
1929    /// Indicates the number of "routers" multicast packets will transit for
1930    /// this socket. The default value is 1 which means that multicast packets
1931    /// don't leave the local network unless explicitly requested.
1932    #[cfg(not(target_os = "wasi"))]
1933    pub fn set_multicast_hops_v6(&self, hops: u32) -> io::Result<()> {
1934        unsafe {
1935            setsockopt(
1936                self.as_raw(),
1937                sys::IPPROTO_IPV6,
1938                sys::IPV6_MULTICAST_HOPS,
1939                hops as c_int,
1940            )
1941        }
1942    }
1943
1944    /// Get the value of the `IPV6_MULTICAST_ALL` option for this socket.
1945    ///
1946    /// For more information about this option, see [`set_multicast_all_v6`].
1947    ///
1948    /// [`set_multicast_all_v6`]: Socket::set_multicast_all_v6
1949    #[cfg(all(feature = "all", target_os = "linux"))]
1950    pub fn multicast_all_v6(&self) -> io::Result<bool> {
1951        unsafe {
1952            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, libc::IPV6_MULTICAST_ALL)
1953                .map(|all| all != 0)
1954        }
1955    }
1956
1957    /// Set the value of the `IPV6_MULTICAST_ALL` option for this socket.
1958    ///
1959    /// This option can be used to modify the delivery policy of
1960    /// multicast messages.  The argument is a boolean
1961    /// (defaults to true).  If set to true, the socket will receive
1962    /// messages from all the groups that have been joined
1963    /// globally on the whole system.  Otherwise, it will deliver
1964    /// messages only from the groups that have been explicitly
1965    /// joined (for example via the `IPV6_ADD_MEMBERSHIP` option) on
1966    /// this particular socket.
1967    #[cfg(all(feature = "all", target_os = "linux"))]
1968    pub fn set_multicast_all_v6(&self, all: bool) -> io::Result<()> {
1969        unsafe {
1970            setsockopt(
1971                self.as_raw(),
1972                sys::IPPROTO_IPV6,
1973                libc::IPV6_MULTICAST_ALL,
1974                all as c_int,
1975            )
1976        }
1977    }
1978
1979    /// Get the value of the `IPV6_MULTICAST_IF` option for this socket.
1980    ///
1981    /// For more information about this option, see [`set_multicast_if_v6`].
1982    ///
1983    /// [`set_multicast_if_v6`]: Socket::set_multicast_if_v6
1984    #[cfg(not(target_os = "wasi"))]
1985    pub fn multicast_if_v6(&self) -> io::Result<u32> {
1986        unsafe {
1987            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_MULTICAST_IF)
1988                .map(|interface| interface as u32)
1989        }
1990    }
1991
1992    /// Set the value of the `IPV6_MULTICAST_IF` option for this socket.
1993    ///
1994    /// Specifies the interface to use for routing multicast packets. Unlike
1995    /// ipv4, this is generally required in ipv6 contexts where network routing
1996    /// prefixes may overlap.
1997    #[cfg(not(target_os = "wasi"))]
1998    pub fn set_multicast_if_v6(&self, interface: u32) -> io::Result<()> {
1999        unsafe {
2000            setsockopt(
2001                self.as_raw(),
2002                sys::IPPROTO_IPV6,
2003                sys::IPV6_MULTICAST_IF,
2004                interface as c_int,
2005            )
2006        }
2007    }
2008
2009    /// Get the value of the `IPV6_MULTICAST_LOOP` option for this socket.
2010    ///
2011    /// For more information about this option, see [`set_multicast_loop_v6`].
2012    ///
2013    /// [`set_multicast_loop_v6`]: Socket::set_multicast_loop_v6
2014    pub fn multicast_loop_v6(&self) -> io::Result<bool> {
2015        unsafe {
2016            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_MULTICAST_LOOP)
2017                .map(|loop_v6| loop_v6 != 0)
2018        }
2019    }
2020
2021    /// Set the value of the `IPV6_MULTICAST_LOOP` option for this socket.
2022    ///
2023    /// Controls whether this socket sees the multicast packets it sends itself.
2024    /// Note that this may not have any affect on IPv4 sockets.
2025    pub fn set_multicast_loop_v6(&self, loop_v6: bool) -> io::Result<()> {
2026        unsafe {
2027            setsockopt(
2028                self.as_raw(),
2029                sys::IPPROTO_IPV6,
2030                sys::IPV6_MULTICAST_LOOP,
2031                loop_v6 as c_int,
2032            )
2033        }
2034    }
2035
2036    /// Get the value of the `IPV6_UNICAST_HOPS` option for this socket.
2037    ///
2038    /// Specifies the hop limit for ipv6 unicast packets
2039    pub fn unicast_hops_v6(&self) -> io::Result<u32> {
2040        unsafe {
2041            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_UNICAST_HOPS)
2042                .map(|hops| hops as u32)
2043        }
2044    }
2045
2046    /// Set the value for the `IPV6_UNICAST_HOPS` option on this socket.
2047    ///
2048    /// Specifies the hop limit for ipv6 unicast packets
2049    pub fn set_unicast_hops_v6(&self, hops: u32) -> io::Result<()> {
2050        unsafe {
2051            setsockopt(
2052                self.as_raw(),
2053                sys::IPPROTO_IPV6,
2054                sys::IPV6_UNICAST_HOPS,
2055                hops as c_int,
2056            )
2057        }
2058    }
2059
2060    /// Get the value of the `IPV6_V6ONLY` option for this socket.
2061    ///
2062    /// For more information about this option, see [`set_only_v6`].
2063    ///
2064    /// [`set_only_v6`]: Socket::set_only_v6
2065    pub fn only_v6(&self) -> io::Result<bool> {
2066        unsafe {
2067            getsockopt::<Bool>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_V6ONLY)
2068                .map(|only_v6| only_v6 != 0)
2069        }
2070    }
2071
2072    /// Set the value for the `IPV6_V6ONLY` option on this socket.
2073    ///
2074    /// If this is set to `true` then the socket is restricted to sending and
2075    /// receiving IPv6 packets only. In this case two IPv4 and IPv6 applications
2076    /// can bind the same port at the same time.
2077    ///
2078    /// If this is set to `false` then the socket can be used to send and
2079    /// receive packets from an IPv4-mapped IPv6 address.
2080    pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
2081        unsafe {
2082            setsockopt(
2083                self.as_raw(),
2084                sys::IPPROTO_IPV6,
2085                sys::IPV6_V6ONLY,
2086                only_v6 as c_int,
2087            )
2088        }
2089    }
2090
2091    /// Get the value of the `IPV6_RECVTCLASS` option for this socket.
2092    ///
2093    /// For more information about this option, see [`set_recv_tclass_v6`].
2094    ///
2095    /// [`set_recv_tclass_v6`]: Socket::set_recv_tclass_v6
2096    #[cfg(not(any(
2097        target_os = "dragonfly",
2098        target_os = "fuchsia",
2099        target_os = "illumos",
2100        target_os = "netbsd",
2101        target_os = "openbsd",
2102        target_os = "redox",
2103        target_os = "solaris",
2104        target_os = "haiku",
2105        target_os = "hurd",
2106        target_os = "espidf",
2107        target_os = "nuttx",
2108        target_os = "vita",
2109        target_os = "wasi",
2110        target_os = "horizon"
2111    )))]
2112    pub fn recv_tclass_v6(&self) -> io::Result<bool> {
2113        unsafe {
2114            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_RECVTCLASS)
2115                .map(|recv_tclass| recv_tclass > 0)
2116        }
2117    }
2118
2119    /// Set the value of the `IPV6_RECVTCLASS` option for this socket.
2120    ///
2121    /// If enabled, the `IPV6_TCLASS` ancillary message is passed with incoming
2122    /// packets. It contains a byte which specifies the traffic class field of
2123    /// the packet header.
2124    #[cfg(not(any(
2125        target_os = "dragonfly",
2126        target_os = "fuchsia",
2127        target_os = "illumos",
2128        target_os = "netbsd",
2129        target_os = "openbsd",
2130        target_os = "redox",
2131        target_os = "solaris",
2132        target_os = "haiku",
2133        target_os = "hurd",
2134        target_os = "espidf",
2135        target_os = "nuttx",
2136        target_os = "vita",
2137        target_os = "wasi",
2138        target_os = "horizon"
2139    )))]
2140    pub fn set_recv_tclass_v6(&self, recv_tclass: bool) -> io::Result<()> {
2141        unsafe {
2142            setsockopt(
2143                self.as_raw(),
2144                sys::IPPROTO_IPV6,
2145                sys::IPV6_RECVTCLASS,
2146                recv_tclass as c_int,
2147            )
2148        }
2149    }
2150
2151    /// Get the value of the `IPV6_RECVHOPLIMIT` option for this socket.
2152    ///
2153    /// For more information about this option, see [`set_recv_hoplimit_v6`].
2154    ///
2155    /// [`set_recv_hoplimit_v6`]: Socket::set_recv_hoplimit_v6
2156    #[cfg(all(
2157        feature = "all",
2158        not(any(
2159            windows,
2160            target_os = "dragonfly",
2161            target_os = "fuchsia",
2162            target_os = "illumos",
2163            target_os = "netbsd",
2164            target_os = "openbsd",
2165            target_os = "redox",
2166            target_os = "solaris",
2167            target_os = "haiku",
2168            target_os = "hurd",
2169            target_os = "espidf",
2170            target_os = "vita",
2171            target_os = "cygwin",
2172            target_os = "wasi",
2173            target_os = "horizon"
2174        ))
2175    ))]
2176    pub fn recv_hoplimit_v6(&self) -> io::Result<bool> {
2177        unsafe {
2178            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_RECVHOPLIMIT)
2179                .map(|recv_hoplimit| recv_hoplimit > 0)
2180        }
2181    }
2182    /// Set the value of the `IPV6_RECVHOPLIMIT` option for this socket.
2183    ///
2184    /// The received hop limit is returned as ancillary data by recvmsg()
2185    /// only if the application has enabled the IPV6_RECVHOPLIMIT socket
2186    /// option:
2187    #[cfg(all(
2188        feature = "all",
2189        not(any(
2190            windows,
2191            target_os = "dragonfly",
2192            target_os = "fuchsia",
2193            target_os = "illumos",
2194            target_os = "netbsd",
2195            target_os = "openbsd",
2196            target_os = "redox",
2197            target_os = "solaris",
2198            target_os = "haiku",
2199            target_os = "hurd",
2200            target_os = "espidf",
2201            target_os = "vita",
2202            target_os = "cygwin",
2203            target_os = "wasi",
2204            target_os = "horizon"
2205        ))
2206    ))]
2207    pub fn set_recv_hoplimit_v6(&self, recv_hoplimit: bool) -> io::Result<()> {
2208        unsafe {
2209            setsockopt(
2210                self.as_raw(),
2211                sys::IPPROTO_IPV6,
2212                sys::IPV6_RECVHOPLIMIT,
2213                recv_hoplimit as c_int,
2214            )
2215        }
2216    }
2217
2218    /// Get the value for the `IP6T_SO_ORIGINAL_DST` option on this socket.
2219    #[cfg(all(
2220        feature = "all",
2221        any(target_os = "android", target_os = "linux", target_os = "windows")
2222    ))]
2223    pub fn original_dst_v6(&self) -> io::Result<SockAddr> {
2224        sys::original_dst_v6(self.as_raw())
2225    }
2226}
2227
2228/// Socket options for TCP sockets, get/set using `IPPROTO_TCP`.
2229///
2230/// Additional documentation can be found in documentation of the OS.
2231/// * Linux: <https://man7.org/linux/man-pages/man7/tcp.7.html>
2232/// * Windows: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-tcp-socket-options>
2233impl Socket {
2234    /// Get the value of the `TCP_KEEPIDLE` option on this socket.
2235    ///
2236    /// This returns the value of `TCP_KEEPALIVE` on macOS and iOS and `TCP_KEEPIDLE` on all other
2237    /// supported Unix operating systems.
2238    #[cfg(all(
2239        feature = "all",
2240        not(any(
2241            windows,
2242            target_os = "haiku",
2243            target_os = "openbsd",
2244            target_os = "vita"
2245        ))
2246    ))]
2247    pub fn tcp_keepalive_time(&self) -> io::Result<Duration> {
2248        sys::tcp_keepalive_time(self.as_raw())
2249    }
2250
2251    /// Get the value of the `TCP_KEEPINTVL` option on this socket.
2252    ///
2253    /// For more information about this option, see [`set_tcp_keepalive`].
2254    ///
2255    /// [`set_tcp_keepalive`]: Socket::set_tcp_keepalive
2256    #[cfg(all(
2257        feature = "all",
2258        any(
2259            target_os = "android",
2260            target_os = "dragonfly",
2261            target_os = "emscripten",
2262            target_os = "freebsd",
2263            target_os = "fuchsia",
2264            target_os = "illumos",
2265            target_os = "ios",
2266            target_os = "visionos",
2267            target_os = "linux",
2268            target_os = "macos",
2269            target_os = "netbsd",
2270            target_os = "tvos",
2271            target_os = "watchos",
2272            target_os = "cygwin",
2273            target_os = "nuttx",
2274            all(target_os = "wasi", not(target_env = "p1")),
2275        )
2276    ))]
2277    pub fn tcp_keepalive_interval(&self) -> io::Result<Duration> {
2278        unsafe {
2279            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_TCP, sys::TCP_KEEPINTVL)
2280                .map(|secs| Duration::from_secs(secs as u64))
2281        }
2282    }
2283
2284    /// Get the value of the `TCP_KEEPCNT` option on this socket.
2285    ///
2286    /// For more information about this option, see [`set_tcp_keepalive`].
2287    ///
2288    /// [`set_tcp_keepalive`]: Socket::set_tcp_keepalive
2289    #[cfg(all(
2290        feature = "all",
2291        any(
2292            target_os = "android",
2293            target_os = "dragonfly",
2294            target_os = "emscripten",
2295            target_os = "freebsd",
2296            target_os = "fuchsia",
2297            target_os = "illumos",
2298            target_os = "ios",
2299            target_os = "visionos",
2300            target_os = "linux",
2301            target_os = "macos",
2302            target_os = "netbsd",
2303            target_os = "tvos",
2304            target_os = "watchos",
2305            target_os = "cygwin",
2306            target_os = "windows",
2307            target_os = "nuttx",
2308            all(target_os = "wasi", not(target_env = "p1")),
2309        )
2310    ))]
2311    pub fn tcp_keepalive_retries(&self) -> io::Result<u32> {
2312        unsafe {
2313            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_TCP, sys::TCP_KEEPCNT)
2314                .map(|retries| retries as u32)
2315        }
2316    }
2317
2318    /// Set parameters configuring TCP keepalive probes for this socket.
2319    ///
2320    /// The supported parameters depend on the operating system, and are
2321    /// configured using the [`TcpKeepalive`] struct. At a minimum, all systems
2322    /// support configuring the [keepalive time]: the time after which the OS
2323    /// will start sending keepalive messages on an idle connection.
2324    ///
2325    /// [keepalive time]: TcpKeepalive::with_time
2326    ///
2327    /// # Notes
2328    ///
2329    /// * This will enable `SO_KEEPALIVE` on this socket, if it is not already
2330    ///   enabled.
2331    /// * On some platforms, such as Windows, any keepalive parameters *not*
2332    ///   configured by the `TcpKeepalive` struct passed to this function may be
2333    ///   overwritten with their default values. Therefore, this function should
2334    ///   either only be called once per socket, or the same parameters should
2335    ///   be passed every time it is called.
2336    ///
2337    /// # Examples
2338    ///
2339    /// ```
2340    /// use std::time::Duration;
2341    ///
2342    /// use socket2::{Socket, TcpKeepalive, Domain, Type};
2343    ///
2344    /// # fn main() -> std::io::Result<()> {
2345    /// let socket = Socket::new(Domain::IPV4, Type::STREAM, None)?;
2346    /// let keepalive = TcpKeepalive::new()
2347    ///     .with_time(Duration::from_secs(4));
2348    ///     // Depending on the target operating system, we may also be able to
2349    ///     // configure the keepalive probe interval and/or the number of
2350    ///     // retries here as well.
2351    ///
2352    /// socket.set_tcp_keepalive(&keepalive)?;
2353    /// # Ok(()) }
2354    /// ```
2355    ///
2356    pub fn set_tcp_keepalive(&self, params: &TcpKeepalive) -> io::Result<()> {
2357        self.set_keepalive(true)?;
2358        sys::set_tcp_keepalive(self.as_raw(), params)
2359    }
2360
2361    /// Get the value of the `TCP_NODELAY` option on this socket.
2362    ///
2363    /// For more information about this option, see [`set_tcp_nodelay`].
2364    ///
2365    /// [`set_tcp_nodelay`]: Socket::set_tcp_nodelay
2366    pub fn tcp_nodelay(&self) -> io::Result<bool> {
2367        unsafe {
2368            getsockopt::<Bool>(self.as_raw(), sys::IPPROTO_TCP, sys::TCP_NODELAY)
2369                .map(|nodelay| nodelay != 0)
2370        }
2371    }
2372
2373    /// Set the value of the `TCP_NODELAY` option on this socket.
2374    ///
2375    /// If set, this option disables the Nagle algorithm. This means that
2376    /// segments are always sent as soon as possible, even if there is only a
2377    /// small amount of data. When not set, data is buffered until there is a
2378    /// sufficient amount to send out, thereby avoiding the frequent sending of
2379    /// small packets.
2380    pub fn set_tcp_nodelay(&self, nodelay: bool) -> io::Result<()> {
2381        unsafe {
2382            setsockopt(
2383                self.as_raw(),
2384                sys::IPPROTO_TCP,
2385                sys::TCP_NODELAY,
2386                nodelay as c_int,
2387            )
2388        }
2389    }
2390
2391    /// On Windows this invokes the `SIO_TCP_SET_ACK_FREQUENCY` IOCTL which
2392    /// configures the number of TCP segments that must be received before
2393    /// the delayed ACK timer is ignored.
2394    #[cfg(all(feature = "all", windows))]
2395    pub fn set_tcp_ack_frequency(&self, frequency: u8) -> io::Result<()> {
2396        sys::set_tcp_ack_frequency(self.as_raw(), frequency)
2397    }
2398}
2399
2400impl Read for Socket {
2401    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
2402        // Safety: the `recv` implementation promises not to write uninitialised
2403        // bytes to the `buf`fer, so this casting is safe.
2404        let buf = unsafe { &mut *(buf as *mut [u8] as *mut [MaybeUninit<u8>]) };
2405        self.recv(buf)
2406    }
2407
2408    #[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
2409    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
2410        // Safety: both `IoSliceMut` and `MaybeUninitSlice` promise to have the
2411        // same layout, that of `iovec`/`WSABUF`. Furthermore, `recv_vectored`
2412        // promises to not write uninitialised bytes to the `bufs` and pass it
2413        // directly to the `recvmsg` system call, so this is safe.
2414        let bufs = unsafe { &mut *(bufs as *mut [IoSliceMut<'_>] as *mut [MaybeUninitSlice<'_>]) };
2415        self.recv_vectored(bufs).map(|(n, _)| n)
2416    }
2417}
2418
2419impl<'a> Read for &'a Socket {
2420    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
2421        // Safety: see other `Read::read` impl.
2422        let buf = unsafe { &mut *(buf as *mut [u8] as *mut [MaybeUninit<u8>]) };
2423        self.recv(buf)
2424    }
2425
2426    #[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
2427    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
2428        // Safety: see other `Read::read` impl.
2429        let bufs = unsafe { &mut *(bufs as *mut [IoSliceMut<'_>] as *mut [MaybeUninitSlice<'_>]) };
2430        self.recv_vectored(bufs).map(|(n, _)| n)
2431    }
2432}
2433
2434impl Write for Socket {
2435    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
2436        self.send(buf)
2437    }
2438
2439    #[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
2440    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
2441        self.send_vectored(bufs)
2442    }
2443
2444    fn flush(&mut self) -> io::Result<()> {
2445        Ok(())
2446    }
2447}
2448
2449impl<'a> Write for &'a Socket {
2450    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
2451        self.send(buf)
2452    }
2453
2454    #[cfg(not(any(target_os = "redox", target_os = "wasi", target_os = "horizon")))]
2455    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
2456        self.send_vectored(bufs)
2457    }
2458
2459    fn flush(&mut self) -> io::Result<()> {
2460        Ok(())
2461    }
2462}
2463
2464impl fmt::Debug for Socket {
2465    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2466        f.debug_struct("Socket")
2467            .field("raw", &self.as_raw())
2468            .field("local_addr", &self.local_addr().ok())
2469            .field("peer_addr", &self.peer_addr().ok())
2470            .finish()
2471    }
2472}
2473
2474from!(net::TcpStream, Socket);
2475from!(net::TcpListener, Socket);
2476from!(net::UdpSocket, Socket);
2477from!(Socket, net::TcpStream);
2478from!(Socket, net::TcpListener);
2479from!(Socket, net::UdpSocket);