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