socket2_plus/
socket.rs

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