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