Skip to main content

socket2/
socket.rs

1// Copyright 2015 The Rust Project Developers.
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use std::fmt;
10use std::io::{self, Read, Write};
11#[cfg(not(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_accept_flags(socket)?;
289            // `set_common_flags` does not disable inheritance on Windows because `Socket::new`
290            // unlike `accept` is able to create the socket with inheritance disabled.
291            #[cfg(windows)]
292            socket._set_no_inherit(true)?;
293            Ok((socket, addr))
294        }
295    }
296
297    /// Accept a new incoming connection from this listener.
298    ///
299    /// This function directly corresponds to the `accept(2)` function on
300    /// Windows and Unix.
301    pub fn accept_raw(&self) -> io::Result<(Socket, SockAddr)> {
302        sys::accept(self.as_raw()).map(|(inner, addr)| (Socket::from_raw(inner), addr))
303    }
304
305    /// Returns the socket address of the local half of this socket.
306    ///
307    /// This function directly corresponds to the `getsockname(2)` function on
308    /// Windows and Unix.
309    #[doc = man_links!(getsockname(2))]
310    ///
311    /// # Notes
312    ///
313    /// Depending on the OS this may return an error if the socket is not
314    /// [bound].
315    ///
316    /// [bound]: Socket::bind
317    pub fn local_addr(&self) -> io::Result<SockAddr> {
318        sys::getsockname(self.as_raw())
319    }
320
321    /// Returns the socket address of the remote peer of this socket.
322    ///
323    /// This function directly corresponds to the `getpeername(2)` function on
324    /// Windows and Unix.
325    #[doc = man_links!(getpeername(2))]
326    ///
327    /// # Notes
328    ///
329    /// This returns an error if the socket is not [`connect`ed].
330    ///
331    /// [`connect`ed]: Socket::connect
332    pub fn peer_addr(&self) -> io::Result<SockAddr> {
333        sys::getpeername(self.as_raw())
334    }
335
336    /// Returns the [`Type`] of this socket by checking the `SO_TYPE` option on
337    /// this socket.
338    pub fn r#type(&self) -> io::Result<Type> {
339        unsafe { getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_TYPE).map(Type) }
340    }
341
342    /// Creates a new independently owned handle to the underlying socket.
343    ///
344    /// # Notes
345    ///
346    /// On Unix this uses `F_DUPFD_CLOEXEC` and thus sets the `FD_CLOEXEC` on
347    /// the returned socket.
348    ///
349    /// On Windows this uses `WSA_FLAG_NO_HANDLE_INHERIT` setting inheriting to
350    /// false.
351    ///
352    /// On Windows this can **not** be used function cannot be used on a
353    /// QOS-enabled socket, see
354    /// <https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsaduplicatesocketw>.
355    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 address 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///
766/// Sockets created via `accept` should use `set_common_accept_flags` instead.
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/// Set `FD_CLOEXEC` on the `socket` for platforms that need it.
802///
803/// Unlike `set_common_flags` we don't set `NOSIGPIPE` as that is inherited from
804/// the listener. Furthermore, attempts to set it on a unix socket domain
805/// results in an error.
806#[cfg(not(any(
807    target_os = "android",
808    target_os = "dragonfly",
809    target_os = "freebsd",
810    target_os = "fuchsia",
811    target_os = "illumos",
812    target_os = "linux",
813    target_os = "netbsd",
814    target_os = "openbsd",
815    target_os = "cygwin",
816)))]
817fn set_common_accept_flags(socket: Socket) -> io::Result<Socket> {
818    // On platforms that don't have `SOCK_CLOEXEC` use `FD_CLOEXEC`.
819    #[cfg(all(
820        unix,
821        not(any(
822            target_os = "android",
823            target_os = "dragonfly",
824            target_os = "freebsd",
825            target_os = "fuchsia",
826            target_os = "hurd",
827            target_os = "illumos",
828            target_os = "linux",
829            target_os = "netbsd",
830            target_os = "openbsd",
831            target_os = "espidf",
832            target_os = "vita",
833            target_os = "cygwin",
834        ))
835    ))]
836    socket._set_cloexec(true)?;
837
838    Ok(socket)
839}
840
841/// A local interface specified by its index or an address assigned to it.
842///
843/// `Index(0)` and `Address(Ipv4Addr::UNSPECIFIED)` are equivalent and indicate
844/// that an appropriate interface should be selected by the system.
845#[cfg(not(any(
846    target_os = "haiku",
847    target_os = "illumos",
848    target_os = "netbsd",
849    target_os = "redox",
850    target_os = "solaris",
851)))]
852#[derive(Debug, Copy, Clone)]
853pub enum InterfaceIndexOrAddress {
854    /// An interface index.
855    Index(u32),
856    /// An address assigned to an interface.
857    Address(Ipv4Addr),
858}
859
860/// Socket options get/set using `SOL_SOCKET`.
861///
862/// Additional documentation can be found in documentation of the OS.
863/// * Linux: <https://man7.org/linux/man-pages/man7/socket.7.html>
864/// * Windows: <https://docs.microsoft.com/en-us/windows/win32/winsock/sol-socket-socket-options>
865impl Socket {
866    /// Get the value of the `SO_BROADCAST` option for this socket.
867    ///
868    /// For more information about this option, see [`set_broadcast`].
869    ///
870    /// [`set_broadcast`]: Socket::set_broadcast
871    pub fn broadcast(&self) -> io::Result<bool> {
872        unsafe {
873            getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_BROADCAST)
874                .map(|broadcast| broadcast != 0)
875        }
876    }
877
878    /// Set the value of the `SO_BROADCAST` option for this socket.
879    ///
880    /// When enabled, this socket is allowed to send packets to a broadcast
881    /// address.
882    pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> {
883        unsafe {
884            setsockopt(
885                self.as_raw(),
886                sys::SOL_SOCKET,
887                sys::SO_BROADCAST,
888                broadcast as c_int,
889            )
890        }
891    }
892
893    /// Get the value of the `SO_ERROR` option on this socket.
894    ///
895    /// This will retrieve the stored error in the underlying socket, clearing
896    /// the field in the process. This can be useful for checking errors between
897    /// calls.
898    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
899        match unsafe { getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_ERROR) } {
900            Ok(0) => Ok(None),
901            Ok(errno) => Ok(Some(io::Error::from_raw_os_error(errno))),
902            Err(err) => Err(err),
903        }
904    }
905
906    /// Get the value of the `SO_KEEPALIVE` option on this socket.
907    ///
908    /// For more information about this option, see [`set_keepalive`].
909    ///
910    /// [`set_keepalive`]: Socket::set_keepalive
911    pub fn keepalive(&self) -> io::Result<bool> {
912        unsafe {
913            getsockopt::<Bool>(self.as_raw(), sys::SOL_SOCKET, sys::SO_KEEPALIVE)
914                .map(|keepalive| keepalive != false as Bool)
915        }
916    }
917
918    /// Set value for the `SO_KEEPALIVE` option on this socket.
919    ///
920    /// Enable sending of keep-alive messages on connection-oriented sockets.
921    pub fn set_keepalive(&self, keepalive: bool) -> io::Result<()> {
922        unsafe {
923            setsockopt(
924                self.as_raw(),
925                sys::SOL_SOCKET,
926                sys::SO_KEEPALIVE,
927                keepalive as c_int,
928            )
929        }
930    }
931
932    /// Get the value of the `SO_LINGER` option on this socket.
933    ///
934    /// For more information about this option, see [`set_linger`].
935    ///
936    /// [`set_linger`]: Socket::set_linger
937    pub fn linger(&self) -> io::Result<Option<Duration>> {
938        unsafe {
939            getsockopt::<sys::linger>(self.as_raw(), sys::SOL_SOCKET, sys::SO_LINGER)
940                .map(from_linger)
941        }
942    }
943
944    /// Set value for the `SO_LINGER` option on this socket.
945    ///
946    /// If `linger` is not `None`, a close(2) or shutdown(2) will not return
947    /// until all queued messages for the socket have been successfully sent or
948    /// the linger timeout has been reached. Otherwise, the call returns
949    /// immediately and the closing is done in the background. When the socket
950    /// is closed as part of exit(2), it always lingers in the background.
951    ///
952    /// # Notes
953    ///
954    /// On most OSs the duration only has a precision of seconds and will be
955    /// silently truncated.
956    ///
957    /// On Apple platforms (e.g. macOS, iOS, etc) this uses `SO_LINGER_SEC`.
958    pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
959        let linger = into_linger(linger);
960        unsafe { setsockopt(self.as_raw(), sys::SOL_SOCKET, sys::SO_LINGER, linger) }
961    }
962
963    /// Get value for the `SO_OOBINLINE` option on this socket.
964    ///
965    /// For more information about this option, see [`set_out_of_band_inline`].
966    ///
967    /// [`set_out_of_band_inline`]: Socket::set_out_of_band_inline
968    #[cfg(not(target_os = "redox"))]
969    pub fn out_of_band_inline(&self) -> io::Result<bool> {
970        unsafe {
971            getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_OOBINLINE)
972                .map(|oob_inline| oob_inline != 0)
973        }
974    }
975
976    /// Set value for the `SO_OOBINLINE` option on this socket.
977    ///
978    /// If this option is enabled, out-of-band data is directly placed into the
979    /// receive data stream. Otherwise, out-of-band data is passed only when the
980    /// `MSG_OOB` flag is set during receiving. As per RFC6093, TCP sockets
981    /// using the Urgent mechanism are encouraged to set this flag.
982    #[cfg(not(target_os = "redox"))]
983    pub fn set_out_of_band_inline(&self, oob_inline: bool) -> io::Result<()> {
984        unsafe {
985            setsockopt(
986                self.as_raw(),
987                sys::SOL_SOCKET,
988                sys::SO_OOBINLINE,
989                oob_inline as c_int,
990            )
991        }
992    }
993
994    /// Get value for the `SO_PASSCRED` option on this socket.
995    ///
996    /// For more information about this option, see [`set_passcred`].
997    ///
998    /// [`set_passcred`]: Socket::set_passcred
999    #[cfg(any(target_os = "linux", target_os = "cygwin"))]
1000    pub fn passcred(&self) -> io::Result<bool> {
1001        unsafe {
1002            getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_PASSCRED)
1003                .map(|passcred| passcred != 0)
1004        }
1005    }
1006
1007    /// Set value for the `SO_PASSCRED` option on this socket.
1008    ///
1009    /// If this option is enabled, enables the receiving of the `SCM_CREDENTIALS`
1010    /// control messages.
1011    #[cfg(any(target_os = "linux", target_os = "cygwin"))]
1012    pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
1013        unsafe {
1014            setsockopt(
1015                self.as_raw(),
1016                sys::SOL_SOCKET,
1017                sys::SO_PASSCRED,
1018                passcred as c_int,
1019            )
1020        }
1021    }
1022
1023    /// Get value for the `SO_PRIORITY` option on this socket.
1024    ///
1025    /// For more information about this option, see [`set_priority`].
1026    ///
1027    /// [`set_priority`]: Socket::set_priority
1028    #[cfg(all(
1029        feature = "all",
1030        any(target_os = "linux", target_os = "android", target_os = "fuchsia")
1031    ))]
1032    pub fn priority(&self) -> io::Result<u32> {
1033        unsafe {
1034            getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_PRIORITY)
1035                .map(|prio| prio as u32)
1036        }
1037    }
1038
1039    /// Set value for the `SO_PRIORITY` option on this socket.
1040    ///
1041    /// Packets with a higher priority may be processed earlier depending on the selected device
1042    /// queueing discipline.
1043    #[cfg(all(
1044        feature = "all",
1045        any(target_os = "linux", target_os = "android", target_os = "fuchsia")
1046    ))]
1047    pub fn set_priority(&self, priority: u32) -> io::Result<()> {
1048        unsafe {
1049            setsockopt(
1050                self.as_raw(),
1051                sys::SOL_SOCKET,
1052                sys::SO_PRIORITY,
1053                priority as c_int,
1054            )
1055        }
1056    }
1057
1058    /// Get value for the `SO_RCVBUF` option on this socket.
1059    ///
1060    /// For more information about this option, see [`set_recv_buffer_size`].
1061    ///
1062    /// [`set_recv_buffer_size`]: Socket::set_recv_buffer_size
1063    pub fn recv_buffer_size(&self) -> io::Result<usize> {
1064        unsafe {
1065            getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_RCVBUF)
1066                .map(|size| size as usize)
1067        }
1068    }
1069
1070    /// Set value for the `SO_RCVBUF` option on this socket.
1071    ///
1072    /// Changes the size of the operating system's receive buffer associated
1073    /// with the socket.
1074    pub fn set_recv_buffer_size(&self, size: usize) -> io::Result<()> {
1075        unsafe {
1076            setsockopt(
1077                self.as_raw(),
1078                sys::SOL_SOCKET,
1079                sys::SO_RCVBUF,
1080                size as c_int,
1081            )
1082        }
1083    }
1084
1085    /// Get value for the `SO_RCVTIMEO` option on this socket.
1086    ///
1087    /// If the returned timeout is `None`, then `read` and `recv` calls will
1088    /// block indefinitely.
1089    pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
1090        sys::timeout_opt(self.as_raw(), sys::SOL_SOCKET, sys::SO_RCVTIMEO)
1091    }
1092
1093    /// Set value for the `SO_RCVTIMEO` option on this socket.
1094    ///
1095    /// If `timeout` is `None`, then `read` and `recv` calls will block
1096    /// indefinitely.
1097    pub fn set_read_timeout(&self, duration: Option<Duration>) -> io::Result<()> {
1098        sys::set_timeout_opt(self.as_raw(), sys::SOL_SOCKET, sys::SO_RCVTIMEO, duration)
1099    }
1100
1101    /// Get the value of the `SO_REUSEADDR` option on this socket.
1102    ///
1103    /// For more information about this option, see [`set_reuse_address`].
1104    ///
1105    /// [`set_reuse_address`]: Socket::set_reuse_address
1106    pub fn reuse_address(&self) -> io::Result<bool> {
1107        unsafe {
1108            getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_REUSEADDR)
1109                .map(|reuse| reuse != 0)
1110        }
1111    }
1112
1113    /// Set value for the `SO_REUSEADDR` option on this socket.
1114    ///
1115    /// This indicates that further calls to `bind` may allow reuse of local
1116    /// addresses. For IPv4 sockets this means that a socket may bind even when
1117    /// there's a socket already listening on this port.
1118    pub fn set_reuse_address(&self, reuse: bool) -> io::Result<()> {
1119        unsafe {
1120            setsockopt(
1121                self.as_raw(),
1122                sys::SOL_SOCKET,
1123                sys::SO_REUSEADDR,
1124                reuse as c_int,
1125            )
1126        }
1127    }
1128
1129    /// Get the value of the `SO_SNDBUF` option on this socket.
1130    ///
1131    /// For more information about this option, see [`set_send_buffer_size`].
1132    ///
1133    /// [`set_send_buffer_size`]: Socket::set_send_buffer_size
1134    pub fn send_buffer_size(&self) -> io::Result<usize> {
1135        unsafe {
1136            getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_SNDBUF)
1137                .map(|size| size as usize)
1138        }
1139    }
1140
1141    /// Set value for the `SO_SNDBUF` option on this socket.
1142    ///
1143    /// Changes the size of the operating system's send buffer associated with
1144    /// the socket.
1145    pub fn set_send_buffer_size(&self, size: usize) -> io::Result<()> {
1146        unsafe {
1147            setsockopt(
1148                self.as_raw(),
1149                sys::SOL_SOCKET,
1150                sys::SO_SNDBUF,
1151                size as c_int,
1152            )
1153        }
1154    }
1155
1156    /// Get value for the `SO_SNDTIMEO` option on this socket.
1157    ///
1158    /// If the returned timeout is `None`, then `write` and `send` calls will
1159    /// block indefinitely.
1160    pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
1161        sys::timeout_opt(self.as_raw(), sys::SOL_SOCKET, sys::SO_SNDTIMEO)
1162    }
1163
1164    /// Set value for the `SO_SNDTIMEO` option on this socket.
1165    ///
1166    /// If `timeout` is `None`, then `write` and `send` calls will block
1167    /// indefinitely.
1168    pub fn set_write_timeout(&self, duration: Option<Duration>) -> io::Result<()> {
1169        sys::set_timeout_opt(self.as_raw(), sys::SOL_SOCKET, sys::SO_SNDTIMEO, duration)
1170    }
1171}
1172
1173const fn from_linger(linger: sys::linger) -> Option<Duration> {
1174    if linger.l_onoff == 0 {
1175        None
1176    } else {
1177        Some(Duration::from_secs(linger.l_linger as u64))
1178    }
1179}
1180
1181const fn into_linger(duration: Option<Duration>) -> sys::linger {
1182    match duration {
1183        Some(duration) => sys::linger {
1184            l_onoff: 1,
1185            l_linger: duration.as_secs() as _,
1186        },
1187        None => sys::linger {
1188            l_onoff: 0,
1189            l_linger: 0,
1190        },
1191    }
1192}
1193
1194/// Socket options for IPv4 sockets, get/set using `IPPROTO_IP` or `SOL_IP`.
1195///
1196/// Additional documentation can be found in documentation of the OS.
1197/// * Linux: <https://man7.org/linux/man-pages/man7/ip.7.html>
1198/// * Windows: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options>
1199impl Socket {
1200    /// Get the value of the `IP_HDRINCL` option on this socket.
1201    ///
1202    /// For more information about this option, see [`set_header_included_v4`].
1203    ///
1204    /// [`set_header_included_v4`]: Socket::set_header_included_v4
1205    #[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))]
1206    pub fn header_included_v4(&self) -> io::Result<bool> {
1207        unsafe {
1208            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_HDRINCL)
1209                .map(|included| included != 0)
1210        }
1211    }
1212
1213    /// Set the value of the `IP_HDRINCL` option on this socket.
1214    ///
1215    /// If enabled, the user supplies an IP header in front of the user data.
1216    /// Valid only for [`SOCK_RAW`] sockets; see [raw(7)] for more information.
1217    /// When this flag is enabled, the values set by `IP_OPTIONS`, [`IP_TTL`],
1218    /// and [`IP_TOS`] are ignored.
1219    ///
1220    /// [`SOCK_RAW`]: Type::RAW
1221    /// [raw(7)]: https://man7.org/linux/man-pages/man7/raw.7.html
1222    /// [`IP_TTL`]: Socket::set_ttl_v4
1223    /// [`IP_TOS`]: Socket::set_tos_v4
1224    #[cfg_attr(
1225        any(target_os = "fuchsia", target_os = "illumos", target_os = "solaris"),
1226        allow(rustdoc::broken_intra_doc_links)
1227    )]
1228    #[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))]
1229    pub fn set_header_included_v4(&self, included: bool) -> io::Result<()> {
1230        unsafe {
1231            setsockopt(
1232                self.as_raw(),
1233                sys::IPPROTO_IP,
1234                sys::IP_HDRINCL,
1235                included as c_int,
1236            )
1237        }
1238    }
1239
1240    /// Get the value of the `IP_TRANSPARENT` option on this socket.
1241    ///
1242    /// For more information about this option, see [`set_ip_transparent_v4`].
1243    ///
1244    /// [`set_ip_transparent_v4`]: Socket::set_ip_transparent_v4
1245    #[cfg(all(feature = "all", target_os = "linux"))]
1246    pub fn ip_transparent_v4(&self) -> io::Result<bool> {
1247        unsafe {
1248            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, libc::IP_TRANSPARENT)
1249                .map(|transparent| transparent != 0)
1250        }
1251    }
1252
1253    /// Set the value of the `IP_TRANSPARENT` option on this socket.
1254    ///
1255    /// Setting this boolean option enables transparent proxying
1256    /// on this socket.  This socket option allows the calling
1257    /// application to bind to a nonlocal IP address and operate
1258    /// both as a client and a server with the foreign address as
1259    /// the local endpoint.  NOTE: this requires that routing be
1260    /// set up in a way that packets going to the foreign address
1261    /// are routed through the TProxy box (i.e., the system
1262    /// hosting the application that employs the IP_TRANSPARENT
1263    /// socket option).  Enabling this socket option requires
1264    /// superuser privileges (the `CAP_NET_ADMIN` capability).
1265    ///
1266    /// TProxy redirection with the iptables TPROXY target also
1267    /// requires that this option be set on the redirected socket.
1268    #[cfg(all(feature = "all", target_os = "linux"))]
1269    pub fn set_ip_transparent_v4(&self, transparent: bool) -> io::Result<()> {
1270        unsafe {
1271            setsockopt(
1272                self.as_raw(),
1273                sys::IPPROTO_IP,
1274                libc::IP_TRANSPARENT,
1275                transparent as c_int,
1276            )
1277        }
1278    }
1279
1280    /// Join a multicast group using `IP_ADD_MEMBERSHIP` option on this socket.
1281    ///
1282    /// This function specifies a new multicast group for this socket to join.
1283    /// The address must be a valid multicast address, and `interface` is the
1284    /// address of the local interface with which the system should join the
1285    /// multicast group. If it's [`Ipv4Addr::UNSPECIFIED`] (`INADDR_ANY`) then
1286    /// an appropriate interface is chosen by the system.
1287    pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
1288        let mreq = sys::IpMreq {
1289            imr_multiaddr: sys::to_in_addr(multiaddr),
1290            imr_interface: sys::to_in_addr(interface),
1291        };
1292        unsafe { setsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_ADD_MEMBERSHIP, mreq) }
1293    }
1294
1295    /// Leave a multicast group using `IP_DROP_MEMBERSHIP` option on this socket.
1296    ///
1297    /// For more information about this option, see [`join_multicast_v4`].
1298    ///
1299    /// [`join_multicast_v4`]: Socket::join_multicast_v4
1300    pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
1301        let mreq = sys::IpMreq {
1302            imr_multiaddr: sys::to_in_addr(multiaddr),
1303            imr_interface: sys::to_in_addr(interface),
1304        };
1305        unsafe {
1306            setsockopt(
1307                self.as_raw(),
1308                sys::IPPROTO_IP,
1309                sys::IP_DROP_MEMBERSHIP,
1310                mreq,
1311            )
1312        }
1313    }
1314
1315    /// Join a multicast group using `IP_ADD_MEMBERSHIP` option on this socket.
1316    ///
1317    /// This function specifies a new multicast group for this socket to join.
1318    /// The address must be a valid multicast address, and `interface` specifies
1319    /// the local interface with which the system should join the multicast
1320    /// group. See [`InterfaceIndexOrAddress`].
1321    #[cfg(not(any(
1322        target_os = "aix",
1323        target_os = "haiku",
1324        target_os = "illumos",
1325        target_os = "netbsd",
1326        target_os = "openbsd",
1327        target_os = "redox",
1328        target_os = "solaris",
1329        target_os = "nto",
1330        target_os = "espidf",
1331        target_os = "vita",
1332        target_os = "cygwin",
1333    )))]
1334    pub fn join_multicast_v4_n(
1335        &self,
1336        multiaddr: &Ipv4Addr,
1337        interface: &InterfaceIndexOrAddress,
1338    ) -> io::Result<()> {
1339        let mreqn = sys::to_mreqn(multiaddr, interface);
1340        unsafe {
1341            setsockopt(
1342                self.as_raw(),
1343                sys::IPPROTO_IP,
1344                sys::IP_ADD_MEMBERSHIP,
1345                mreqn,
1346            )
1347        }
1348    }
1349
1350    /// Leave a multicast group using `IP_DROP_MEMBERSHIP` option on this socket.
1351    ///
1352    /// For more information about this option, see [`join_multicast_v4_n`].
1353    ///
1354    /// [`join_multicast_v4_n`]: Socket::join_multicast_v4_n
1355    #[cfg(not(any(
1356        target_os = "aix",
1357        target_os = "haiku",
1358        target_os = "illumos",
1359        target_os = "netbsd",
1360        target_os = "openbsd",
1361        target_os = "redox",
1362        target_os = "solaris",
1363        target_os = "nto",
1364        target_os = "espidf",
1365        target_os = "vita",
1366        target_os = "cygwin",
1367    )))]
1368    pub fn leave_multicast_v4_n(
1369        &self,
1370        multiaddr: &Ipv4Addr,
1371        interface: &InterfaceIndexOrAddress,
1372    ) -> io::Result<()> {
1373        let mreqn = sys::to_mreqn(multiaddr, interface);
1374        unsafe {
1375            setsockopt(
1376                self.as_raw(),
1377                sys::IPPROTO_IP,
1378                sys::IP_DROP_MEMBERSHIP,
1379                mreqn,
1380            )
1381        }
1382    }
1383
1384    /// Join a multicast SSM channel using `IP_ADD_SOURCE_MEMBERSHIP` option on this socket.
1385    ///
1386    /// This function specifies a new multicast channel for this socket to join.
1387    /// The group must be a valid SSM group address, the source must be the address of the sender
1388    /// and `interface` is the address of the local interface with which the system should join the
1389    /// multicast group. If it's [`Ipv4Addr::UNSPECIFIED`] (`INADDR_ANY`) then
1390    /// an appropriate interface is chosen by the system.
1391    #[cfg(not(any(
1392        target_os = "dragonfly",
1393        target_os = "haiku",
1394        target_os = "hurd",
1395        target_os = "netbsd",
1396        target_os = "openbsd",
1397        target_os = "redox",
1398        target_os = "fuchsia",
1399        target_os = "nto",
1400        target_os = "espidf",
1401        target_os = "vita",
1402    )))]
1403    pub fn join_ssm_v4(
1404        &self,
1405        source: &Ipv4Addr,
1406        group: &Ipv4Addr,
1407        interface: &Ipv4Addr,
1408    ) -> io::Result<()> {
1409        let mreqs = sys::IpMreqSource {
1410            imr_multiaddr: sys::to_in_addr(group),
1411            imr_interface: sys::to_in_addr(interface),
1412            imr_sourceaddr: sys::to_in_addr(source),
1413        };
1414        unsafe {
1415            setsockopt(
1416                self.as_raw(),
1417                sys::IPPROTO_IP,
1418                sys::IP_ADD_SOURCE_MEMBERSHIP,
1419                mreqs,
1420            )
1421        }
1422    }
1423
1424    /// Leave a multicast group using `IP_DROP_SOURCE_MEMBERSHIP` option on this socket.
1425    ///
1426    /// For more information about this option, see [`join_ssm_v4`].
1427    ///
1428    /// [`join_ssm_v4`]: Socket::join_ssm_v4
1429    #[cfg(not(any(
1430        target_os = "dragonfly",
1431        target_os = "haiku",
1432        target_os = "hurd",
1433        target_os = "netbsd",
1434        target_os = "openbsd",
1435        target_os = "redox",
1436        target_os = "fuchsia",
1437        target_os = "nto",
1438        target_os = "espidf",
1439        target_os = "vita",
1440    )))]
1441    pub fn leave_ssm_v4(
1442        &self,
1443        source: &Ipv4Addr,
1444        group: &Ipv4Addr,
1445        interface: &Ipv4Addr,
1446    ) -> io::Result<()> {
1447        let mreqs = sys::IpMreqSource {
1448            imr_multiaddr: sys::to_in_addr(group),
1449            imr_interface: sys::to_in_addr(interface),
1450            imr_sourceaddr: sys::to_in_addr(source),
1451        };
1452        unsafe {
1453            setsockopt(
1454                self.as_raw(),
1455                sys::IPPROTO_IP,
1456                sys::IP_DROP_SOURCE_MEMBERSHIP,
1457                mreqs,
1458            )
1459        }
1460    }
1461
1462    /// Get the value of the `IP_MULTICAST_ALL` option for this socket.
1463    ///
1464    /// For more information about this option, see [`set_multicast_all_v4`].
1465    ///
1466    /// [`set_multicast_all_v4`]: Socket::set_multicast_all_v4
1467    #[cfg(all(feature = "all", target_os = "linux"))]
1468    pub fn multicast_all_v4(&self) -> io::Result<bool> {
1469        unsafe {
1470            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, libc::IP_MULTICAST_ALL)
1471                .map(|all| all != 0)
1472        }
1473    }
1474
1475    /// Set the value of the `IP_MULTICAST_ALL` option for this socket.
1476    ///
1477    /// This option can be used to modify the delivery policy of
1478    /// multicast messages.  The argument is a boolean
1479    /// (defaults to true).  If set to true, the socket will receive
1480    /// messages from all the groups that have been joined
1481    /// globally on the whole system.  Otherwise, it will deliver
1482    /// messages only from the groups that have been explicitly
1483    /// joined (for example via the `IP_ADD_MEMBERSHIP` option) on
1484    /// this particular socket.
1485    #[cfg(all(feature = "all", target_os = "linux"))]
1486    pub fn set_multicast_all_v4(&self, all: bool) -> io::Result<()> {
1487        unsafe {
1488            setsockopt(
1489                self.as_raw(),
1490                sys::IPPROTO_IP,
1491                libc::IP_MULTICAST_ALL,
1492                all as c_int,
1493            )
1494        }
1495    }
1496
1497    /// Get the value of the `IP_MULTICAST_IF` option for this socket.
1498    ///
1499    /// For more information about this option, see [`set_multicast_if_v4`].
1500    ///
1501    /// [`set_multicast_if_v4`]: Socket::set_multicast_if_v4
1502    pub fn multicast_if_v4(&self) -> io::Result<Ipv4Addr> {
1503        unsafe {
1504            getsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_MULTICAST_IF).map(sys::from_in_addr)
1505        }
1506    }
1507
1508    /// Set the value of the `IP_MULTICAST_IF` option for this socket.
1509    ///
1510    /// Specifies the interface to use for routing multicast packets.
1511    pub fn set_multicast_if_v4(&self, interface: &Ipv4Addr) -> io::Result<()> {
1512        let interface = sys::to_in_addr(interface);
1513        unsafe {
1514            setsockopt(
1515                self.as_raw(),
1516                sys::IPPROTO_IP,
1517                sys::IP_MULTICAST_IF,
1518                interface,
1519            )
1520        }
1521    }
1522
1523    /// Get the value of the `IP_MULTICAST_LOOP` option for this socket.
1524    ///
1525    /// For more information about this option, see [`set_multicast_loop_v4`].
1526    ///
1527    /// [`set_multicast_loop_v4`]: Socket::set_multicast_loop_v4
1528    pub fn multicast_loop_v4(&self) -> io::Result<bool> {
1529        unsafe {
1530            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_MULTICAST_LOOP)
1531                .map(|loop_v4| loop_v4 != 0)
1532        }
1533    }
1534
1535    /// Set the value of the `IP_MULTICAST_LOOP` option for this socket.
1536    ///
1537    /// If enabled, multicast packets will be looped back to the local socket.
1538    /// Note that this may not have any affect on IPv6 sockets.
1539    pub fn set_multicast_loop_v4(&self, loop_v4: bool) -> io::Result<()> {
1540        unsafe {
1541            setsockopt(
1542                self.as_raw(),
1543                sys::IPPROTO_IP,
1544                sys::IP_MULTICAST_LOOP,
1545                loop_v4 as c_int,
1546            )
1547        }
1548    }
1549
1550    /// Get the value of the `IP_MULTICAST_TTL` option for this socket.
1551    ///
1552    /// For more information about this option, see [`set_multicast_ttl_v4`].
1553    ///
1554    /// [`set_multicast_ttl_v4`]: Socket::set_multicast_ttl_v4
1555    pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
1556        unsafe {
1557            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_MULTICAST_TTL)
1558                .map(|ttl| ttl as u32)
1559        }
1560    }
1561
1562    /// Set the value of the `IP_MULTICAST_TTL` option for this socket.
1563    ///
1564    /// Indicates the time-to-live value of outgoing multicast packets for
1565    /// this socket. The default value is 1 which means that multicast packets
1566    /// don't leave the local network unless explicitly requested.
1567    ///
1568    /// Note that this may not have any affect on IPv6 sockets.
1569    pub fn set_multicast_ttl_v4(&self, ttl: u32) -> io::Result<()> {
1570        unsafe {
1571            setsockopt(
1572                self.as_raw(),
1573                sys::IPPROTO_IP,
1574                sys::IP_MULTICAST_TTL,
1575                ttl as c_int,
1576            )
1577        }
1578    }
1579
1580    /// Get the value of the `IP_TTL` option for this socket.
1581    ///
1582    /// For more information about this option, see [`set_ttl_v4`].
1583    ///
1584    /// [`set_ttl_v4`]: Socket::set_ttl_v4
1585    pub fn ttl_v4(&self) -> io::Result<u32> {
1586        unsafe {
1587            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_TTL).map(|ttl| ttl as u32)
1588        }
1589    }
1590
1591    /// Set the value of the `IP_TTL` option for this socket.
1592    ///
1593    /// This value sets the time-to-live field that is used in every packet sent
1594    /// from this socket.
1595    pub fn set_ttl_v4(&self, ttl: u32) -> io::Result<()> {
1596        unsafe { setsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_TTL, ttl as c_int) }
1597    }
1598
1599    /// Set the value of the `IP_TOS` option for this socket.
1600    ///
1601    /// This value sets the type-of-service field that is used in every packet
1602    /// sent from this socket.
1603    ///
1604    /// NOTE: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options>
1605    /// documents that not all versions of windows support `IP_TOS`.
1606    #[cfg(not(any(
1607        target_os = "fuchsia",
1608        target_os = "redox",
1609        target_os = "solaris",
1610        target_os = "illumos",
1611        target_os = "haiku",
1612    )))]
1613    pub fn set_tos_v4(&self, tos: u32) -> io::Result<()> {
1614        unsafe { setsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_TOS, tos as c_int) }
1615    }
1616
1617    /// Get the value of the `IP_TOS` option for this socket.
1618    ///
1619    /// For more information about this option, see [`set_tos_v4`].
1620    ///
1621    /// NOTE: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options>
1622    /// documents that not all versions of windows support `IP_TOS`.
1623    ///
1624    /// [`set_tos_v4`]: Socket::set_tos_v4
1625    #[cfg(not(any(
1626        target_os = "fuchsia",
1627        target_os = "redox",
1628        target_os = "solaris",
1629        target_os = "illumos",
1630        target_os = "haiku",
1631    )))]
1632    pub fn tos_v4(&self) -> io::Result<u32> {
1633        unsafe {
1634            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_TOS).map(|tos| tos as u32)
1635        }
1636    }
1637
1638    /// Set the value of the `IP_RECVTOS` option for this socket.
1639    ///
1640    /// If enabled, the `IP_TOS` ancillary message is passed with
1641    /// incoming packets. It contains a byte which specifies the
1642    /// Type of Service/Precedence field of the packet header.
1643    #[cfg(not(any(
1644        target_os = "aix",
1645        target_os = "dragonfly",
1646        target_os = "fuchsia",
1647        target_os = "hurd",
1648        target_os = "illumos",
1649        target_os = "netbsd",
1650        target_os = "openbsd",
1651        target_os = "redox",
1652        target_os = "solaris",
1653        target_os = "haiku",
1654        target_os = "nto",
1655        target_os = "espidf",
1656        target_os = "vita",
1657        target_os = "cygwin",
1658    )))]
1659    pub fn set_recv_tos_v4(&self, recv_tos: bool) -> io::Result<()> {
1660        unsafe {
1661            setsockopt(
1662                self.as_raw(),
1663                sys::IPPROTO_IP,
1664                sys::IP_RECVTOS,
1665                recv_tos as c_int,
1666            )
1667        }
1668    }
1669
1670    /// Get the value of the `IP_RECVTOS` option for this socket.
1671    ///
1672    /// For more information about this option, see [`set_recv_tos_v4`].
1673    ///
1674    /// [`set_recv_tos_v4`]: Socket::set_recv_tos_v4
1675    #[cfg(not(any(
1676        target_os = "aix",
1677        target_os = "dragonfly",
1678        target_os = "fuchsia",
1679        target_os = "hurd",
1680        target_os = "illumos",
1681        target_os = "netbsd",
1682        target_os = "openbsd",
1683        target_os = "redox",
1684        target_os = "solaris",
1685        target_os = "haiku",
1686        target_os = "nto",
1687        target_os = "espidf",
1688        target_os = "vita",
1689        target_os = "cygwin",
1690    )))]
1691    pub fn recv_tos_v4(&self) -> io::Result<bool> {
1692        unsafe {
1693            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_RECVTOS)
1694                .map(|recv_tos| recv_tos > 0)
1695        }
1696    }
1697
1698    /// Get the value for the `SO_ORIGINAL_DST` option on this socket.
1699    #[cfg(all(
1700        feature = "all",
1701        any(
1702            target_os = "android",
1703            target_os = "fuchsia",
1704            target_os = "linux",
1705            target_os = "windows",
1706        )
1707    ))]
1708    pub fn original_dst_v4(&self) -> io::Result<SockAddr> {
1709        sys::original_dst_v4(self.as_raw())
1710    }
1711}
1712
1713/// Socket options for IPv6 sockets, get/set using `IPPROTO_IPV6` or `SOL_IPV6`.
1714///
1715/// Additional documentation can be found in documentation of the OS.
1716/// * Linux: <https://man7.org/linux/man-pages/man7/ipv6.7.html>
1717/// * Windows: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ipv6-socket-options>
1718impl Socket {
1719    /// Get the value of the `IP_HDRINCL` option on this socket.
1720    ///
1721    /// For more information about this option, see [`set_header_included_v6`].
1722    ///
1723    /// [`set_header_included_v6`]: Socket::set_header_included_v6
1724    #[cfg(all(
1725        feature = "all",
1726        not(any(
1727            target_os = "redox",
1728            target_os = "espidf",
1729            target_os = "openbsd",
1730            target_os = "freebsd",
1731            target_os = "dragonfly",
1732            target_os = "netbsd"
1733        ))
1734    ))]
1735    pub fn header_included_v6(&self) -> io::Result<bool> {
1736        unsafe {
1737            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IP_HDRINCL)
1738                .map(|included| included != 0)
1739        }
1740    }
1741
1742    /// Set the value of the `IP_HDRINCL` option on this socket.
1743    ///
1744    /// If enabled, the user supplies an IP header in front of the user data.
1745    /// Valid only for [`SOCK_RAW`] sockets; see [raw(7)] for more information.
1746    /// When this flag is enabled, the values set by `IP_OPTIONS` are ignored.
1747    ///
1748    /// [`SOCK_RAW`]: Type::RAW
1749    /// [raw(7)]: https://man7.org/linux/man-pages/man7/raw.7.html
1750    #[cfg_attr(
1751        any(target_os = "fuchsia", target_os = "illumos", target_os = "solaris"),
1752        allow(rustdoc::broken_intra_doc_links)
1753    )]
1754    #[cfg(all(
1755        feature = "all",
1756        not(any(
1757            target_os = "redox",
1758            target_os = "espidf",
1759            target_os = "openbsd",
1760            target_os = "freebsd",
1761            target_os = "dragonfly",
1762            target_os = "netbsd"
1763        ))
1764    ))]
1765    pub fn set_header_included_v6(&self, included: bool) -> io::Result<()> {
1766        unsafe {
1767            setsockopt(
1768                self.as_raw(),
1769                sys::IPPROTO_IPV6,
1770                #[cfg(target_os = "linux")]
1771                sys::IPV6_HDRINCL,
1772                #[cfg(not(target_os = "linux"))]
1773                sys::IP_HDRINCL,
1774                included as c_int,
1775            )
1776        }
1777    }
1778
1779    /// Join a multicast group using `IPV6_ADD_MEMBERSHIP` option on this socket.
1780    ///
1781    /// Some OSs use `IPV6_JOIN_GROUP` for this option.
1782    ///
1783    /// This function specifies a new multicast group for this socket to join.
1784    /// The address must be a valid multicast address, and `interface` is the
1785    /// index of the interface to join/leave (or 0 to indicate any interface).
1786    #[cfg(not(target_os = "nto"))]
1787    pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
1788        let mreq = sys::Ipv6Mreq {
1789            ipv6mr_multiaddr: sys::to_in6_addr(multiaddr),
1790            // NOTE: some OSs use `c_int`, others use `c_uint`.
1791            ipv6mr_interface: interface as _,
1792        };
1793        unsafe {
1794            setsockopt(
1795                self.as_raw(),
1796                sys::IPPROTO_IPV6,
1797                sys::IPV6_ADD_MEMBERSHIP,
1798                mreq,
1799            )
1800        }
1801    }
1802
1803    /// Leave a multicast group using `IPV6_DROP_MEMBERSHIP` option on this socket.
1804    ///
1805    /// Some OSs use `IPV6_LEAVE_GROUP` for this option.
1806    ///
1807    /// For more information about this option, see [`join_multicast_v6`].
1808    ///
1809    /// [`join_multicast_v6`]: Socket::join_multicast_v6
1810    #[cfg(not(target_os = "nto"))]
1811    pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
1812        let mreq = sys::Ipv6Mreq {
1813            ipv6mr_multiaddr: sys::to_in6_addr(multiaddr),
1814            // NOTE: some OSs use `c_int`, others use `c_uint`.
1815            ipv6mr_interface: interface as _,
1816        };
1817        unsafe {
1818            setsockopt(
1819                self.as_raw(),
1820                sys::IPPROTO_IPV6,
1821                sys::IPV6_DROP_MEMBERSHIP,
1822                mreq,
1823            )
1824        }
1825    }
1826
1827    /// Get the value of the `IPV6_MULTICAST_HOPS` option for this socket
1828    ///
1829    /// For more information about this option, see [`set_multicast_hops_v6`].
1830    ///
1831    /// [`set_multicast_hops_v6`]: Socket::set_multicast_hops_v6
1832    pub fn multicast_hops_v6(&self) -> io::Result<u32> {
1833        unsafe {
1834            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_MULTICAST_HOPS)
1835                .map(|hops| hops as u32)
1836        }
1837    }
1838
1839    /// Set the value of the `IPV6_MULTICAST_HOPS` option for this socket
1840    ///
1841    /// Indicates the number of "routers" multicast packets will transit for
1842    /// this socket. The default value is 1 which means that multicast packets
1843    /// don't leave the local network unless explicitly requested.
1844    pub fn set_multicast_hops_v6(&self, hops: u32) -> io::Result<()> {
1845        unsafe {
1846            setsockopt(
1847                self.as_raw(),
1848                sys::IPPROTO_IPV6,
1849                sys::IPV6_MULTICAST_HOPS,
1850                hops as c_int,
1851            )
1852        }
1853    }
1854
1855    /// Get the value of the `IPV6_MULTICAST_ALL` option for this socket.
1856    ///
1857    /// For more information about this option, see [`set_multicast_all_v6`].
1858    ///
1859    /// [`set_multicast_all_v6`]: Socket::set_multicast_all_v6
1860    #[cfg(all(feature = "all", target_os = "linux"))]
1861    pub fn multicast_all_v6(&self) -> io::Result<bool> {
1862        unsafe {
1863            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, libc::IPV6_MULTICAST_ALL)
1864                .map(|all| all != 0)
1865        }
1866    }
1867
1868    /// Set the value of the `IPV6_MULTICAST_ALL` option for this socket.
1869    ///
1870    /// This option can be used to modify the delivery policy of
1871    /// multicast messages.  The argument is a boolean
1872    /// (defaults to true).  If set to true, the socket will receive
1873    /// messages from all the groups that have been joined
1874    /// globally on the whole system.  Otherwise, it will deliver
1875    /// messages only from the groups that have been explicitly
1876    /// joined (for example via the `IPV6_ADD_MEMBERSHIP` option) on
1877    /// this particular socket.
1878    #[cfg(all(feature = "all", target_os = "linux"))]
1879    pub fn set_multicast_all_v6(&self, all: bool) -> io::Result<()> {
1880        unsafe {
1881            setsockopt(
1882                self.as_raw(),
1883                sys::IPPROTO_IPV6,
1884                libc::IPV6_MULTICAST_ALL,
1885                all as c_int,
1886            )
1887        }
1888    }
1889
1890    /// Get the value of the `IPV6_MULTICAST_IF` option for this socket.
1891    ///
1892    /// For more information about this option, see [`set_multicast_if_v6`].
1893    ///
1894    /// [`set_multicast_if_v6`]: Socket::set_multicast_if_v6
1895    pub fn multicast_if_v6(&self) -> io::Result<u32> {
1896        unsafe {
1897            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_MULTICAST_IF)
1898                .map(|interface| interface as u32)
1899        }
1900    }
1901
1902    /// Set the value of the `IPV6_MULTICAST_IF` option for this socket.
1903    ///
1904    /// Specifies the interface to use for routing multicast packets. Unlike
1905    /// ipv4, this is generally required in ipv6 contexts where network routing
1906    /// prefixes may overlap.
1907    pub fn set_multicast_if_v6(&self, interface: u32) -> io::Result<()> {
1908        unsafe {
1909            setsockopt(
1910                self.as_raw(),
1911                sys::IPPROTO_IPV6,
1912                sys::IPV6_MULTICAST_IF,
1913                interface as c_int,
1914            )
1915        }
1916    }
1917
1918    /// Get the value of the `IPV6_MULTICAST_LOOP` option for this socket.
1919    ///
1920    /// For more information about this option, see [`set_multicast_loop_v6`].
1921    ///
1922    /// [`set_multicast_loop_v6`]: Socket::set_multicast_loop_v6
1923    pub fn multicast_loop_v6(&self) -> io::Result<bool> {
1924        unsafe {
1925            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_MULTICAST_LOOP)
1926                .map(|loop_v6| loop_v6 != 0)
1927        }
1928    }
1929
1930    /// Set the value of the `IPV6_MULTICAST_LOOP` option for this socket.
1931    ///
1932    /// Controls whether this socket sees the multicast packets it sends itself.
1933    /// Note that this may not have any affect on IPv4 sockets.
1934    pub fn set_multicast_loop_v6(&self, loop_v6: bool) -> io::Result<()> {
1935        unsafe {
1936            setsockopt(
1937                self.as_raw(),
1938                sys::IPPROTO_IPV6,
1939                sys::IPV6_MULTICAST_LOOP,
1940                loop_v6 as c_int,
1941            )
1942        }
1943    }
1944
1945    /// Get the value of the `IPV6_UNICAST_HOPS` option for this socket.
1946    ///
1947    /// Specifies the hop limit for ipv6 unicast packets
1948    pub fn unicast_hops_v6(&self) -> io::Result<u32> {
1949        unsafe {
1950            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_UNICAST_HOPS)
1951                .map(|hops| hops as u32)
1952        }
1953    }
1954
1955    /// Set the value for the `IPV6_UNICAST_HOPS` option on this socket.
1956    ///
1957    /// Specifies the hop limit for ipv6 unicast packets
1958    pub fn set_unicast_hops_v6(&self, hops: u32) -> io::Result<()> {
1959        unsafe {
1960            setsockopt(
1961                self.as_raw(),
1962                sys::IPPROTO_IPV6,
1963                sys::IPV6_UNICAST_HOPS,
1964                hops as c_int,
1965            )
1966        }
1967    }
1968
1969    /// Get the value of the `IPV6_V6ONLY` option for this socket.
1970    ///
1971    /// For more information about this option, see [`set_only_v6`].
1972    ///
1973    /// [`set_only_v6`]: Socket::set_only_v6
1974    pub fn only_v6(&self) -> io::Result<bool> {
1975        unsafe {
1976            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_V6ONLY)
1977                .map(|only_v6| only_v6 != 0)
1978        }
1979    }
1980
1981    /// Set the value for the `IPV6_V6ONLY` option on this socket.
1982    ///
1983    /// If this is set to `true` then the socket is restricted to sending and
1984    /// receiving IPv6 packets only. In this case two IPv4 and IPv6 applications
1985    /// can bind the same port at the same time.
1986    ///
1987    /// If this is set to `false` then the socket can be used to send and
1988    /// receive packets from an IPv4-mapped IPv6 address.
1989    pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
1990        unsafe {
1991            setsockopt(
1992                self.as_raw(),
1993                sys::IPPROTO_IPV6,
1994                sys::IPV6_V6ONLY,
1995                only_v6 as c_int,
1996            )
1997        }
1998    }
1999
2000    /// Get the value of the `IPV6_RECVTCLASS` option for this socket.
2001    ///
2002    /// For more information about this option, see [`set_recv_tclass_v6`].
2003    ///
2004    /// [`set_recv_tclass_v6`]: Socket::set_recv_tclass_v6
2005    #[cfg(not(any(
2006        target_os = "dragonfly",
2007        target_os = "fuchsia",
2008        target_os = "illumos",
2009        target_os = "netbsd",
2010        target_os = "openbsd",
2011        target_os = "redox",
2012        target_os = "solaris",
2013        target_os = "haiku",
2014        target_os = "hurd",
2015        target_os = "espidf",
2016        target_os = "vita",
2017    )))]
2018    pub fn recv_tclass_v6(&self) -> io::Result<bool> {
2019        unsafe {
2020            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_RECVTCLASS)
2021                .map(|recv_tclass| recv_tclass > 0)
2022        }
2023    }
2024
2025    /// Set the value of the `IPV6_RECVTCLASS` option for this socket.
2026    ///
2027    /// If enabled, the `IPV6_TCLASS` ancillary message is passed with incoming
2028    /// packets. It contains a byte which specifies the traffic class field of
2029    /// the packet header.
2030    #[cfg(not(any(
2031        target_os = "dragonfly",
2032        target_os = "fuchsia",
2033        target_os = "illumos",
2034        target_os = "netbsd",
2035        target_os = "openbsd",
2036        target_os = "redox",
2037        target_os = "solaris",
2038        target_os = "haiku",
2039        target_os = "hurd",
2040        target_os = "espidf",
2041        target_os = "vita",
2042    )))]
2043    pub fn set_recv_tclass_v6(&self, recv_tclass: bool) -> io::Result<()> {
2044        unsafe {
2045            setsockopt(
2046                self.as_raw(),
2047                sys::IPPROTO_IPV6,
2048                sys::IPV6_RECVTCLASS,
2049                recv_tclass as c_int,
2050            )
2051        }
2052    }
2053
2054    /// Get the value of the `IPV6_RECVHOPLIMIT` option for this socket.
2055    ///
2056    /// For more information about this option, see [`set_recv_hoplimit_v6`].
2057    ///
2058    /// [`set_recv_hoplimit_v6`]: Socket::set_recv_hoplimit_v6
2059    #[cfg(all(
2060        feature = "all",
2061        not(any(
2062            windows,
2063            target_os = "dragonfly",
2064            target_os = "fuchsia",
2065            target_os = "illumos",
2066            target_os = "netbsd",
2067            target_os = "openbsd",
2068            target_os = "redox",
2069            target_os = "solaris",
2070            target_os = "haiku",
2071            target_os = "hurd",
2072            target_os = "espidf",
2073            target_os = "vita",
2074            target_os = "cygwin",
2075        ))
2076    ))]
2077    pub fn recv_hoplimit_v6(&self) -> io::Result<bool> {
2078        unsafe {
2079            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_RECVHOPLIMIT)
2080                .map(|recv_hoplimit| recv_hoplimit > 0)
2081        }
2082    }
2083    /// Set the value of the `IPV6_RECVHOPLIMIT` option for this socket.
2084    ///
2085    /// The received hop limit is returned as ancillary data by recvmsg()
2086    /// only if the application has enabled the IPV6_RECVHOPLIMIT socket
2087    /// option:
2088    #[cfg(all(
2089        feature = "all",
2090        not(any(
2091            windows,
2092            target_os = "dragonfly",
2093            target_os = "fuchsia",
2094            target_os = "illumos",
2095            target_os = "netbsd",
2096            target_os = "openbsd",
2097            target_os = "redox",
2098            target_os = "solaris",
2099            target_os = "haiku",
2100            target_os = "hurd",
2101            target_os = "espidf",
2102            target_os = "vita",
2103            target_os = "cygwin",
2104        ))
2105    ))]
2106    pub fn set_recv_hoplimit_v6(&self, recv_hoplimit: bool) -> io::Result<()> {
2107        unsafe {
2108            setsockopt(
2109                self.as_raw(),
2110                sys::IPPROTO_IPV6,
2111                sys::IPV6_RECVHOPLIMIT,
2112                recv_hoplimit as c_int,
2113            )
2114        }
2115    }
2116
2117    /// Get the value for the `IP6T_SO_ORIGINAL_DST` option on this socket.
2118    #[cfg(all(
2119        feature = "all",
2120        any(target_os = "android", target_os = "linux", target_os = "windows")
2121    ))]
2122    pub fn original_dst_v6(&self) -> io::Result<SockAddr> {
2123        sys::original_dst_v6(self.as_raw())
2124    }
2125}
2126
2127/// Socket options for TCP sockets, get/set using `IPPROTO_TCP`.
2128///
2129/// Additional documentation can be found in documentation of the OS.
2130/// * Linux: <https://man7.org/linux/man-pages/man7/tcp.7.html>
2131/// * Windows: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-tcp-socket-options>
2132impl Socket {
2133    /// Get the value of the `TCP_KEEPIDLE` option on this socket.
2134    ///
2135    /// This returns the value of `TCP_KEEPALIVE` on macOS and iOS and `TCP_KEEPIDLE` on all other
2136    /// supported Unix operating systems.
2137    #[cfg(all(
2138        feature = "all",
2139        not(any(
2140            windows,
2141            target_os = "haiku",
2142            target_os = "openbsd",
2143            target_os = "vita"
2144        ))
2145    ))]
2146    pub fn tcp_keepalive_time(&self) -> io::Result<Duration> {
2147        sys::tcp_keepalive_time(self.as_raw())
2148    }
2149
2150    /// Get the value of the `TCP_KEEPINTVL` option on this socket.
2151    ///
2152    /// For more information about this option, see [`set_tcp_keepalive`].
2153    ///
2154    /// [`set_tcp_keepalive`]: Socket::set_tcp_keepalive
2155    #[cfg(all(
2156        feature = "all",
2157        any(
2158            target_os = "android",
2159            target_os = "dragonfly",
2160            target_os = "freebsd",
2161            target_os = "fuchsia",
2162            target_os = "illumos",
2163            target_os = "ios",
2164            target_os = "visionos",
2165            target_os = "linux",
2166            target_os = "macos",
2167            target_os = "netbsd",
2168            target_os = "tvos",
2169            target_os = "watchos",
2170            target_os = "cygwin",
2171        )
2172    ))]
2173    pub fn tcp_keepalive_interval(&self) -> io::Result<Duration> {
2174        unsafe {
2175            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_TCP, sys::TCP_KEEPINTVL)
2176                .map(|secs| Duration::from_secs(secs as u64))
2177        }
2178    }
2179
2180    /// Get the value of the `TCP_KEEPCNT` option on this socket.
2181    ///
2182    /// For more information about this option, see [`set_tcp_keepalive`].
2183    ///
2184    /// [`set_tcp_keepalive`]: Socket::set_tcp_keepalive
2185    #[cfg(all(
2186        feature = "all",
2187        any(
2188            target_os = "android",
2189            target_os = "dragonfly",
2190            target_os = "freebsd",
2191            target_os = "fuchsia",
2192            target_os = "illumos",
2193            target_os = "ios",
2194            target_os = "visionos",
2195            target_os = "linux",
2196            target_os = "macos",
2197            target_os = "netbsd",
2198            target_os = "tvos",
2199            target_os = "watchos",
2200            target_os = "cygwin",
2201            target_os = "windows",
2202        )
2203    ))]
2204    pub fn tcp_keepalive_retries(&self) -> io::Result<u32> {
2205        unsafe {
2206            getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_TCP, sys::TCP_KEEPCNT)
2207                .map(|retries| retries as u32)
2208        }
2209    }
2210
2211    /// Set parameters configuring TCP keepalive probes for this socket.
2212    ///
2213    /// The supported parameters depend on the operating system, and are
2214    /// configured using the [`TcpKeepalive`] struct. At a minimum, all systems
2215    /// support configuring the [keepalive time]: the time after which the OS
2216    /// will start sending keepalive messages on an idle connection.
2217    ///
2218    /// [keepalive time]: TcpKeepalive::with_time
2219    ///
2220    /// # Notes
2221    ///
2222    /// * This will enable `SO_KEEPALIVE` on this socket, if it is not already
2223    ///   enabled.
2224    /// * On some platforms, such as Windows, any keepalive parameters *not*
2225    ///   configured by the `TcpKeepalive` struct passed to this function may be
2226    ///   overwritten with their default values. Therefore, this function should
2227    ///   either only be called once per socket, or the same parameters should
2228    ///   be passed every time it is called.
2229    ///
2230    /// # Examples
2231    ///
2232    /// ```
2233    /// use std::time::Duration;
2234    ///
2235    /// use socket2::{Socket, TcpKeepalive, Domain, Type};
2236    ///
2237    /// # fn main() -> std::io::Result<()> {
2238    /// let socket = Socket::new(Domain::IPV4, Type::STREAM, None)?;
2239    /// let keepalive = TcpKeepalive::new()
2240    ///     .with_time(Duration::from_secs(4));
2241    ///     // Depending on the target operating system, we may also be able to
2242    ///     // configure the keepalive probe interval and/or the number of
2243    ///     // retries here as well.
2244    ///
2245    /// socket.set_tcp_keepalive(&keepalive)?;
2246    /// # Ok(()) }
2247    /// ```
2248    ///
2249    pub fn set_tcp_keepalive(&self, params: &TcpKeepalive) -> io::Result<()> {
2250        self.set_keepalive(true)?;
2251        sys::set_tcp_keepalive(self.as_raw(), params)
2252    }
2253
2254    /// Get the value of the `TCP_NODELAY` option on this socket.
2255    ///
2256    /// For more information about this option, see [`set_tcp_nodelay`].
2257    ///
2258    /// [`set_tcp_nodelay`]: Socket::set_tcp_nodelay
2259    pub fn tcp_nodelay(&self) -> io::Result<bool> {
2260        unsafe {
2261            getsockopt::<Bool>(self.as_raw(), sys::IPPROTO_TCP, sys::TCP_NODELAY)
2262                .map(|nodelay| nodelay != false as Bool)
2263        }
2264    }
2265
2266    /// Set the value of the `TCP_NODELAY` option on this socket.
2267    ///
2268    /// If set, this option disables the Nagle algorithm. This means that
2269    /// segments are always sent as soon as possible, even if there is only a
2270    /// small amount of data. When not set, data is buffered until there is a
2271    /// sufficient amount to send out, thereby avoiding the frequent sending of
2272    /// small packets.
2273    pub fn set_tcp_nodelay(&self, nodelay: bool) -> io::Result<()> {
2274        unsafe {
2275            setsockopt(
2276                self.as_raw(),
2277                sys::IPPROTO_TCP,
2278                sys::TCP_NODELAY,
2279                nodelay as c_int,
2280            )
2281        }
2282    }
2283}
2284
2285impl Read for Socket {
2286    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
2287        // Safety: the `recv` implementation promises not to write uninitialised
2288        // bytes to the `buf`fer, so this casting is safe.
2289        let buf = unsafe { &mut *(buf as *mut [u8] as *mut [MaybeUninit<u8>]) };
2290        self.recv(buf)
2291    }
2292
2293    #[cfg(not(target_os = "redox"))]
2294    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
2295        // Safety: both `IoSliceMut` and `MaybeUninitSlice` promise to have the
2296        // same layout, that of `iovec`/`WSABUF`. Furthermore, `recv_vectored`
2297        // promises to not write uninitialised bytes to the `bufs` and pass it
2298        // directly to the `recvmsg` system call, so this is safe.
2299        let bufs = unsafe { &mut *(bufs as *mut [IoSliceMut<'_>] as *mut [MaybeUninitSlice<'_>]) };
2300        self.recv_vectored(bufs).map(|(n, _)| n)
2301    }
2302}
2303
2304impl<'a> Read for &'a Socket {
2305    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
2306        // Safety: see other `Read::read` impl.
2307        let buf = unsafe { &mut *(buf as *mut [u8] as *mut [MaybeUninit<u8>]) };
2308        self.recv(buf)
2309    }
2310
2311    #[cfg(not(target_os = "redox"))]
2312    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
2313        // Safety: see other `Read::read` impl.
2314        let bufs = unsafe { &mut *(bufs as *mut [IoSliceMut<'_>] as *mut [MaybeUninitSlice<'_>]) };
2315        self.recv_vectored(bufs).map(|(n, _)| n)
2316    }
2317}
2318
2319impl Write for Socket {
2320    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
2321        self.send(buf)
2322    }
2323
2324    #[cfg(not(target_os = "redox"))]
2325    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
2326        self.send_vectored(bufs)
2327    }
2328
2329    fn flush(&mut self) -> io::Result<()> {
2330        Ok(())
2331    }
2332}
2333
2334impl<'a> Write for &'a Socket {
2335    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
2336        self.send(buf)
2337    }
2338
2339    #[cfg(not(target_os = "redox"))]
2340    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
2341        self.send_vectored(bufs)
2342    }
2343
2344    fn flush(&mut self) -> io::Result<()> {
2345        Ok(())
2346    }
2347}
2348
2349impl fmt::Debug for Socket {
2350    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2351        f.debug_struct("Socket")
2352            .field("raw", &self.as_raw())
2353            .field("local_addr", &self.local_addr().ok())
2354            .field("peer_addr", &self.peer_addr().ok())
2355            .finish()
2356    }
2357}
2358
2359from!(net::TcpStream, Socket);
2360from!(net::TcpListener, Socket);
2361from!(net::UdpSocket, Socket);
2362from!(Socket, net::TcpStream);
2363from!(Socket, net::TcpListener);
2364from!(Socket, net::UdpSocket);