diff --git a/.cirrus.yml b/.cirrus.yml index 0cbae5f0..dc68cea5 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -1,5 +1,5 @@ freebsd_instance: - image_family: freebsd-13-2 + image: freebsd-13-2-release-amd64 env: RUST_BACKTRACE: full @@ -7,7 +7,7 @@ env: task: name: FreeBSD setup_script: - - curl https://sh.rustup.rs -sSf --output rustup.sh + - fetch https://sh.rustup.rs -o rustup.sh - sh rustup.sh -y --profile minimal cargo_cache: folder: $HOME/.cargo/registry diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0d83a0e5..20ca0d1c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -51,35 +51,65 @@ jobs: - name: Check formatting run: cargo fmt --all -- --check Check: - name: Check runs-on: ubuntu-latest + timeout-minutes: 10 strategy: fail-fast: false matrix: - target: ["aarch64-apple-ios", "aarch64-linux-android", "x86_64-apple-darwin", "x86_64-unknown-fuchsia", "x86_64-pc-windows-msvc", "x86_64-pc-solaris", "x86_64-unknown-freebsd", "x86_64-unknown-illumos", "x86_64-unknown-linux-gnu", "x86_64-unknown-linux-musl", "x86_64-unknown-netbsd", "x86_64-unknown-redox", "armv7-linux-androideabi", "i686-linux-android"] - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable - with: - targets: ${{ matrix.target }} - - uses: taiki-e/install-action@cargo-hack - - name: Run check - run: cargo hack check --feature-powerset --all-targets --examples --bins --tests --target ${{ matrix.target }} - CheckTier3: - name: Check - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - target: ["armv7-sony-vita-newlibeabihf", "i686-unknown-hurd-gnu"] + target: + - aarch64-apple-darwin + - aarch64-apple-ios + - aarch64-apple-tvos + # Broken, see https://github.com/rust-lang/socket2/issues/538. + #- aarch64-apple-visionos + - aarch64-apple-watchos + - aarch64-linux-android + - aarch64-unknown-freebsd + - aarch64-unknown-linux-gnu + - aarch64-unknown-linux-musl + - aarch64-unknown-linux-ohos + - aarch64-unknown-netbsd + - aarch64-unknown-openbsd + - aarch64-unknown-redox + - arm-linux-androideabi + - arm64_32-apple-watchos + - armv7-linux-androideabi + - armv7-sony-vita-newlibeabihf + - armv7-unknown-linux-ohos + - i686-linux-android + # Broken, see https://github.com/rust-lang/socket2/issues/539. + #- i686-unknown-hurd-gnu + - i686-unknown-linux-gnu + - sparcv9-sun-solaris + - x86_64-apple-darwin + - x86_64-apple-ios + - x86_64-pc-solaris + # Fails with: + # `rror calling dlltool 'x86_64-w64-mingw32-dlltool': No such file or + # directory (os error 2)`, build log: + # . + #- x86_64-pc-windows-gnu + - x86_64-pc-windows-msvc + - x86_64-unknown-dragonfly + - x86_64-unknown-freebsd + - x86_64-unknown-fuchsia + - x86_64-unknown-illumos + - x86_64-unknown-linux-gnu + - x86_64-unknown-linux-musl + - x86_64-unknown-linux-ohos + - x86_64-unknown-netbsd + - x86_64-unknown-openbsd + - x86_64-unknown-redox steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@nightly with: - components: "rust-src" + components: rust-src - uses: taiki-e/install-action@cargo-hack - - name: Run check - run: cargo hack check -Z build-std=std,panic_abort --feature-powerset --all-targets --examples --bins --tests --target ${{ matrix.target }} + - name: Check build + run: cargo hack check -Z build-std=std,panic_abort --feature-powerset --target ${{ matrix.target }} + - name: Check docs + run: RUSTDOCFLAGS="-D warnings --cfg docsrs" cargo doc -Z build-std=std,panic_abort --no-deps --all-features --target ${{ matrix.target }} Clippy: name: Clippy runs-on: ubuntu-latest @@ -88,31 +118,3 @@ jobs: - uses: dtolnay/rust-toolchain@stable - name: Run Clippy run: cargo clippy --all-targets --all-features -- -D warnings - Docs: - name: Docs - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - target: ["aarch64-apple-ios", "aarch64-linux-android", "x86_64-apple-darwin", "x86_64-unknown-fuchsia", "x86_64-pc-windows-msvc", "x86_64-pc-solaris", "x86_64-unknown-freebsd", "x86_64-unknown-illumos", "x86_64-unknown-linux-gnu", "x86_64-unknown-linux-musl", "x86_64-unknown-netbsd", "x86_64-unknown-redox", "armv7-linux-androideabi", "i686-linux-android"] - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@nightly # NOTE: need nightly for `doc_cfg` feature. - with: - targets: ${{ matrix.target }} - - name: Check docs for docs.rs - run: RUSTDOCFLAGS="-D warnings --cfg docsrs" cargo doc --no-deps --all-features --target ${{ matrix.target }} - DocsTier3: - name: Docs - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - target: ["armv7-sony-vita-newlibeabihf", "i686-unknown-hurd-gnu"] - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@nightly # NOTE: need nightly for `doc_cfg` feature. - with: - components: "rust-src" - - name: Check docs for docs.rs - run: RUSTDOCFLAGS="-D warnings --cfg docsrs" cargo doc -Z build-std=std,panic_abort --no-deps --all-features --target ${{ matrix.target }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 49f41310..f416f22c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,21 +1,39 @@ +# 0.5.8 + +* Added `Socket::(set_)header_included_v4` and + `Socket::(set_)header_included_v6` + (https://github.com/rust-lang/socket2/pull/518). +* Added support for `Socket::original_dst` and + `Socket::original_dst_ipv6` on Windows + (https://github.com/rust-lang/socket2/pull/529). + +# 0.5.7 + +* Added `Socket::(set_)passcred` + (https://github.com/rust-lang/socket2/pull/506). +* Added `RecvFlags::is_confirm` and `RecvFlags::is_dontroute` + (https://github.com/rust-lang/socket2/pull/499). +* Added `MsgHdrMut::control_len` + (https://github.com/rust-lang/socket2/pull/505). + # 0.5.6 -* Add `Socket::(set_)multicast_all_v{4,6}` +* Added `Socket::(set_)multicast_all_v{4,6}` (https://github.com/rust-lang/socket2/pull/485 and - (https://github.com/rust-lang/socket2/pull/486). -* Add support for GNU/Hurd + https://github.com/rust-lang/socket2/pull/486). +* Added support for GNU/Hurd (https://github.com/rust-lang/socket2/pull/474). -* Fix compilation on Haiku +* Fixes compilation on Haiku (https://github.com/rust-lang/socket2/pull/479 and - (https://github.com/rust-lang/socket2/pull/482). -* Fix compilation on OpenHarmony + https://github.com/rust-lang/socket2/pull/482). +* Fixes compilation on OpenHarmony (https://github.com/rust-lang/socket2/pull/491). * Update to window-sys v0.52 (https://github.com/rust-lang/socket2/pull/480). # 0.5.5 -* Add support for Vita +* Added support for Vita (https://github.com/rust-lang/socket2/pull/465). # 0.5.4 @@ -35,7 +53,7 @@ (https://github.com/rust-lang/socket2/pull/442). * Added `Protocol::DIVERT` on FreeBSD and OpenBSD (https://github.com/rust-lang/socket2/pull/448). -* Add `Socket::protocol` for Windows (using `WSAPROTOCOL_INFOW`) +* Added `Socket::protocol` for Windows (using `WSAPROTOCOL_INFOW`) (https://github.com/rust-lang/socket2/pull/470). * `From` for `SockAddr ` nows sets `ss_len` on platforms that have the fields (most BSDs) @@ -53,7 +71,7 @@ # 0.5.2 -* Add Unix socket methods to `SockAddr` +* Added Unix socket methods to `SockAddr` (https://github.com/rust-lang/socket2/pull/403 and https://github.com/rust-lang/socket2/pull/429). * Added `SockAddr::as_storage` @@ -167,9 +185,9 @@ * Fixed compilation with the `all` on QNX Neutrino (https://github.com/rust-lang/socket2/pull/419). -* Add support for ESP-IDF +* Added support for ESP-IDF (https://github.com/rust-lang/socket2/pull/455). -* Add support for Vita +* Added support for Vita (https://github.com/rust-lang/socket2/pull/475). # 0.4.9 @@ -181,7 +199,7 @@ This release was broken for Windows. -* Add `Socket::peek_sender` (backport) +* Added `Socket::peek_sender` (backport) (https://github.com/rust-lang/socket2/pull/404). # 0.4.7 @@ -200,7 +218,7 @@ This release was broken for Windows. (https://github.com/rust-lang/socket2/pull/307). * Derive Clone for SockAddr (https://github.com/rust-lang/socket2/pull/311). -* Fix cfg attributes for Fuchsia +* Fixes cfg attributes for Fuchsia (https://github.com/rust-lang/socket2/pull/314). # 0.4.5 (yanked) @@ -219,7 +237,7 @@ This release was broken for Windows. ## Fixed -* Fix OpenBSD build +* OpenBSD build (https://github.com/rust-lang/socket2/pull/291). # 0.4.4 @@ -264,13 +282,13 @@ This release was broken for Windows. ## Added -* Add `SockAddr::new` +* Added `SockAddr::new` * Support for `TCP_USER_TIMEOUT`. * Support for `IP_BOUND_IF`. * Support for `IP_TRANSPARENT`. * Enable `Socket::type` on all platforms. * Support for uclibc (for Haiku support). -* Add DragonFly support for TCP keepalive (`KEEPINTVL`/`KEEPCNT`). +* Added DragonFly support for TCP keepalive (`KEEPINTVL`/`KEEPCNT`). * Documentation for proper use of `SockRef::from`, and the improper use. * Assertion in `SockRef::from` to ensure the raw socket valid. diff --git a/Cargo.toml b/Cargo.toml index 96cc5f13..d0566282 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "socket2" -version = "0.5.6" +version = "0.6.0" +publish = false # In development. authors = [ "Alex Crichton ", "Thomas de Zeeuw " @@ -28,14 +29,29 @@ include = [ [package.metadata.docs.rs] all-features = true -rustdoc-args = ["--cfg", "docsrs"] -targets = ["aarch64-apple-ios", "aarch64-linux-android", "x86_64-apple-darwin", "x86_64-unknown-fuchsia", "x86_64-pc-windows-msvc", "x86_64-pc-solaris", "x86_64-unknown-freebsd", "x86_64-unknown-illumos", "x86_64-unknown-linux-gnu", "x86_64-unknown-linux-musl", "x86_64-unknown-netbsd", "x86_64-unknown-redox", "armv7-linux-androideabi", "i686-linux-android"] +default-target = "x86_64-unknown-linux-gnu" +targets = [ + "aarch64-apple-ios", + "aarch64-linux-android", + "armv7-linux-androideabi", + "i686-linux-android", + "x86_64-apple-darwin", + "x86_64-pc-solaris", + "x86_64-pc-windows-msvc", + "x86_64-unknown-freebsd", + "x86_64-unknown-fuchsia", + "x86_64-unknown-illumos", + "x86_64-unknown-linux-gnu", + "x86_64-unknown-linux-musl", + "x86_64-unknown-netbsd", + "x86_64-unknown-redox", +] [package.metadata.playground] features = ["all"] [target."cfg(unix)".dependencies] -libc = "0.2.150" +libc = "0.2.171" [target.'cfg(windows)'.dependencies.windows-sys] version = "0.52" diff --git a/README.md b/README.md index 8bb09495..d84e40c5 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,7 @@ feature flag. * NetBSD * Redox * Solaris +* OpenHarmony # Minimum Supported Rust Version (MSRV) diff --git a/src/lib.rs b/src/lib.rs index 4f6bd789..4d39b05d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(clippy::needless_lifetimes)] + //! Utilities for creating and using sockets. //! //! The goal of this crate is to create and use a socket using advanced @@ -51,8 +53,8 @@ //! that are not available on all OSs. #![deny(missing_docs, missing_debug_implementations, rust_2018_idioms)] -// Show required OS/features on docs.rs. -#![cfg_attr(docsrs, feature(doc_cfg))] +// Automatically generate required OS/features for docs.rs. +#![cfg_attr(docsrs, feature(doc_auto_cfg))] // Disallow warnings when running tests. #![cfg_attr(test, deny(warnings))] // Disallow warnings in examples. @@ -266,20 +268,14 @@ impl Type { /// /// Used for the DCCP protocol. #[cfg(all(feature = "all", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))] pub const DCCP: Type = Type(sys::SOCK_DCCP); /// Type corresponding to `SOCK_SEQPACKET`. #[cfg(all(feature = "all", not(target_os = "espidf")))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "all", not(target_os = "espidf")))))] pub const SEQPACKET: Type = Type(sys::SOCK_SEQPACKET); /// Type corresponding to `SOCK_RAW`. #[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))] - #[cfg_attr( - docsrs, - doc(cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))) - )] pub const RAW: Type = Type(sys::SOCK_RAW); } @@ -324,7 +320,6 @@ impl Protocol { /// Protocol corresponding to `DCCP`. #[cfg(all(feature = "all", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))] pub const DCCP: Protocol = Protocol(sys::IPPROTO_DCCP); /// Protocol corresponding to `SCTP`. @@ -364,7 +359,6 @@ impl From for c_int { /// /// Flags provide additional information about incoming messages. #[cfg(not(target_os = "redox"))] -#[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))] #[derive(Copy, Clone, Eq, PartialEq)] pub struct RecvFlags(c_int); @@ -455,6 +449,7 @@ pub struct TcpKeepalive { impl TcpKeepalive { /// Returns a new, empty set of TCP keepalive parameters. + #[allow(clippy::new_without_default)] pub const fn new() -> TcpKeepalive { TcpKeepalive { time: None, @@ -514,6 +509,7 @@ impl TcpKeepalive { target_os = "fuchsia", target_os = "illumos", target_os = "ios", + target_os = "visionos", target_os = "linux", target_os = "macos", target_os = "netbsd", @@ -521,23 +517,6 @@ impl TcpKeepalive { target_os = "watchos", target_os = "windows", ))] - #[cfg_attr( - docsrs, - doc(cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "illumos", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "tvos", - target_os = "watchos", - target_os = "windows", - ))) - )] pub const fn with_interval(self, interval: Duration) -> Self { Self { interval: Some(interval), @@ -558,6 +537,7 @@ impl TcpKeepalive { target_os = "fuchsia", target_os = "illumos", target_os = "ios", + target_os = "visionos", target_os = "linux", target_os = "macos", target_os = "netbsd", @@ -565,25 +545,6 @@ impl TcpKeepalive { target_os = "watchos", ) ))] - #[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "illumos", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "tvos", - target_os = "watchos", - ) - ))) - )] pub const fn with_retries(self, retries: u32) -> Self { Self { retries: Some(retries), @@ -719,6 +680,15 @@ impl<'addr, 'bufs, 'control> MsgHdrMut<'addr, 'bufs, 'control> { pub fn flags(&self) -> RecvFlags { sys::msghdr_flags(&self.inner) } + + /// Gets the length of the control buffer. + /// + /// Can be used to determine how much, if any, of the control buffer was filled by `recvmsg`. + /// + /// Corresponds to `msg_controllen` on Unix and `Control.len` on Windows. + pub fn control_len(&self) -> usize { + sys::msghdr_control_len(&self.inner) + } } #[cfg(not(target_os = "redox"))] diff --git a/src/sockaddr.rs b/src/sockaddr.rs index 6df22fdc..c80dccf3 100644 --- a/src/sockaddr.rs +++ b/src/sockaddr.rs @@ -258,7 +258,7 @@ impl SockAddr { /// Returns the initialised storage bytes. fn as_bytes(&self) -> &[u8] { // SAFETY: `self.storage` is a C struct which can always be treated a - // slice of bytes. Futhermore we ensure we don't read any unitialised + // slice of bytes. Furthermore, we ensure we don't read any unitialised // bytes by using `self.len`. unsafe { std::slice::from_raw_parts(self.as_ptr().cast(), self.len as usize) } } @@ -291,6 +291,7 @@ impl From for SockAddr { target_os = "haiku", target_os = "hermit", target_os = "ios", + target_os = "visionos", target_os = "macos", target_os = "netbsd", target_os = "nto", @@ -334,6 +335,7 @@ impl From for SockAddr { target_os = "haiku", target_os = "hermit", target_os = "ios", + target_os = "visionos", target_os = "macos", target_os = "netbsd", target_os = "nto", @@ -358,6 +360,7 @@ impl fmt::Debug for SockAddr { target_os = "haiku", target_os = "hermit", target_os = "ios", + target_os = "visionos", target_os = "macos", target_os = "netbsd", target_os = "nto", diff --git a/src/socket.rs b/src/socket.rs index 3291707c..06cd07f9 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -150,7 +150,6 @@ impl Socket { /// [`Socket::pair_raw`] can be used if you don't want to set those flags. #[doc = man_links!(unix: socketpair(2))] #[cfg(all(feature = "all", unix))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "all", unix))))] pub fn pair( domain: Domain, ty: Type, @@ -167,7 +166,6 @@ impl Socket { /// /// This function corresponds to `socketpair(2)`. #[cfg(all(feature = "all", unix))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "all", unix))))] pub fn pair_raw( domain: Domain, ty: Type, @@ -369,7 +367,6 @@ impl Socket { /// /// On Windows it is not possible retrieve the nonblocking mode status. #[cfg(all(feature = "all", unix))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "all", unix))))] pub fn nonblocking(&self) -> io::Result { sys::nonblocking(self.as_raw()) } @@ -471,7 +468,6 @@ impl Socket { /// function with `buf`s of type `&mut [IoSliceMut]`, allowing initialised /// buffers to be used without using `unsafe`. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))] pub fn recv_vectored( &self, bufs: &mut [MaybeUninitSlice<'_>], @@ -491,7 +487,6 @@ impl Socket { /// /// [`recv_vectored`]: Socket::recv_vectored #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))] pub fn recv_vectored_with_flags( &self, bufs: &mut [MaybeUninitSlice<'_>], @@ -557,7 +552,6 @@ impl Socket { /// /// [`recv_vectored`]: Socket::recv_vectored #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))] pub fn recv_from_vectored( &self, bufs: &mut [MaybeUninitSlice<'_>], @@ -577,7 +571,6 @@ impl Socket { /// /// [`recv_vectored`]: Socket::recv_vectored #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))] pub fn recv_from_vectored_with_flags( &self, bufs: &mut [MaybeUninitSlice<'_>], @@ -637,7 +630,6 @@ impl Socket { /// for an example (in C++). #[doc = man_links!(recvmsg(2))] #[cfg(all(unix, not(target_os = "redox")))] - #[cfg_attr(docsrs, doc(cfg(all(unix, not(target_os = "redox")))))] pub fn recvmsg(&self, msg: &mut MsgHdrMut<'_, '_, '_>, flags: sys::c_int) -> io::Result { sys::recvmsg(self.as_raw(), msg, flags) } @@ -663,7 +655,6 @@ impl Socket { /// Send data to the connected peer. Returns the amount of bytes written. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))] pub fn send_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { self.send_vectored_with_flags(bufs, 0) } @@ -674,7 +665,6 @@ impl Socket { /// /// [`send_vectored`]: Socket::send_vectored #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))] pub fn send_vectored_with_flags( &self, bufs: &[IoSlice<'_>], @@ -721,7 +711,6 @@ impl Socket { /// written. #[doc = man_links!(sendmsg(2))] #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))] pub fn send_to_vectored(&self, bufs: &[IoSlice<'_>], addr: &SockAddr) -> io::Result { self.send_to_vectored_with_flags(bufs, addr, 0) } @@ -731,7 +720,6 @@ impl Socket { /// /// [`send_to_vectored`]: Socket::send_to_vectored #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))] pub fn send_to_vectored_with_flags( &self, bufs: &[IoSlice<'_>], @@ -744,7 +732,6 @@ impl Socket { /// Send a message on a socket using a message structure. #[doc = man_links!(sendmsg(2))] #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))] pub fn sendmsg(&self, msg: &MsgHdr<'_, '_, '_>, flags: sys::c_int) -> io::Result { sys::sendmsg(self.as_raw(), msg, flags) } @@ -801,6 +788,7 @@ fn set_common_flags(socket: Socket) -> io::Result { // On Apple platforms set `NOSIGPIPE`. #[cfg(any( target_os = "ios", + target_os = "visionos", target_os = "macos", target_os = "tvos", target_os = "watchos", @@ -821,7 +809,7 @@ fn set_common_flags(socket: Socket) -> io::Result { target_os = "redox", target_os = "solaris", )))] -#[derive(Debug)] +#[derive(Debug, Copy, Clone)] pub enum InterfaceIndexOrAddress { /// An interface index. Index(u32), @@ -938,7 +926,6 @@ impl Socket { /// /// [`set_out_of_band_inline`]: Socket::set_out_of_band_inline #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))] pub fn out_of_band_inline(&self) -> io::Result { unsafe { getsockopt::(self.as_raw(), sys::SOL_SOCKET, sys::SO_OOBINLINE) @@ -953,7 +940,6 @@ impl Socket { /// `MSG_OOB` flag is set during receiving. As per RFC6093, TCP sockets /// using the Urgent mechanism are encouraged to set this flag. #[cfg(not(target_os = "redox"))] - #[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))] pub fn set_out_of_band_inline(&self, oob_inline: bool) -> io::Result<()> { unsafe { setsockopt( @@ -965,6 +951,35 @@ impl Socket { } } + /// Get value for the `SO_PASSCRED` option on this socket. + /// + /// For more information about this option, see [`set_passcred`]. + /// + /// [`set_passcred`]: Socket::set_passcred + #[cfg(all(unix, target_os = "linux"))] + pub fn passcred(&self) -> io::Result { + unsafe { + getsockopt::(self.as_raw(), sys::SOL_SOCKET, sys::SO_PASSCRED) + .map(|passcred| passcred != 0) + } + } + + /// Set value for the `SO_PASSCRED` option on this socket. + /// + /// If this option is enabled, enables the receiving of the `SCM_CREDENTIALS` + /// control messages. + #[cfg(all(unix, target_os = "linux"))] + pub fn set_passcred(&self, passcred: bool) -> io::Result<()> { + unsafe { + setsockopt( + self.as_raw(), + sys::SOL_SOCKET, + sys::SO_PASSCRED, + passcred as c_int, + ) + } + } + /// Get value for the `SO_RCVBUF` option on this socket. /// /// For more information about this option, see [`set_recv_buffer_size`]. @@ -1022,7 +1037,7 @@ impl Socket { /// Set value for the `SO_REUSEADDR` option on this socket. /// - /// This indicates that futher calls to `bind` may allow reuse of local + /// This indicates that further calls to `bind` may allow reuse of local /// addresses. For IPv4 sockets this means that a socket may bind even when /// there's a socket already listening on this port. pub fn set_reuse_address(&self, reuse: bool) -> io::Result<()> { @@ -1109,15 +1124,11 @@ const fn into_linger(duration: Option) -> sys::linger { impl Socket { /// Get the value of the `IP_HDRINCL` option on this socket. /// - /// For more information about this option, see [`set_header_included`]. + /// For more information about this option, see [`set_header_included_v4`]. /// - /// [`set_header_included`]: Socket::set_header_included + /// [`set_header_included_v4`]: Socket::set_header_included_v4 #[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))] - #[cfg_attr( - docsrs, - doc(cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))) - )] - pub fn header_included(&self) -> io::Result { + pub fn header_included_v4(&self) -> io::Result { unsafe { getsockopt::(self.as_raw(), sys::IPPROTO_IP, sys::IP_HDRINCL) .map(|included| included != 0) @@ -1133,18 +1144,14 @@ impl Socket { /// /// [`SOCK_RAW`]: Type::RAW /// [raw(7)]: https://man7.org/linux/man-pages/man7/raw.7.html - /// [`IP_TTL`]: Socket::set_ttl - /// [`IP_TOS`]: Socket::set_tos + /// [`IP_TTL`]: Socket::set_ttl_v4 + /// [`IP_TOS`]: Socket::set_tos_v4 #[cfg_attr( any(target_os = "fuchsia", target_os = "illumos", target_os = "solaris"), allow(rustdoc::broken_intra_doc_links) )] #[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))] - #[cfg_attr( - docsrs, - doc(cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))) - )] - pub fn set_header_included(&self, included: bool) -> io::Result<()> { + pub fn set_header_included_v4(&self, included: bool) -> io::Result<()> { unsafe { setsockopt( self.as_raw(), @@ -1157,12 +1164,11 @@ impl Socket { /// Get the value of the `IP_TRANSPARENT` option on this socket. /// - /// For more information about this option, see [`set_ip_transparent`]. + /// For more information about this option, see [`set_ip_transparent_v4`]. /// - /// [`set_ip_transparent`]: Socket::set_ip_transparent + /// [`set_ip_transparent_v4`]: Socket::set_ip_transparent_v4 #[cfg(all(feature = "all", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))] - pub fn ip_transparent(&self) -> io::Result { + pub fn ip_transparent_v4(&self) -> io::Result { unsafe { getsockopt::(self.as_raw(), sys::IPPROTO_IP, libc::IP_TRANSPARENT) .map(|transparent| transparent != 0) @@ -1185,8 +1191,7 @@ impl Socket { /// TProxy redirection with the iptables TPROXY target also /// requires that this option be set on the redirected socket. #[cfg(all(feature = "all", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))] - pub fn set_ip_transparent(&self, transparent: bool) -> io::Result<()> { + pub fn set_ip_transparent_v4(&self, transparent: bool) -> io::Result<()> { unsafe { setsockopt( self.as_raw(), @@ -1383,7 +1388,6 @@ impl Socket { /// /// [`set_multicast_all_v4`]: Socket::set_multicast_all_v4 #[cfg(all(feature = "all", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))] pub fn multicast_all_v4(&self) -> io::Result { unsafe { getsockopt::(self.as_raw(), sys::IPPROTO_IP, libc::IP_MULTICAST_ALL) @@ -1402,7 +1406,6 @@ impl Socket { /// joined (for example via the `IP_ADD_MEMBERSHIP` option) on /// this particular socket. #[cfg(all(feature = "all", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))] pub fn set_multicast_all_v4(&self, all: bool) -> io::Result<()> { unsafe { setsockopt( @@ -1499,10 +1502,10 @@ impl Socket { /// Get the value of the `IP_TTL` option for this socket. /// - /// For more information about this option, see [`set_ttl`]. + /// For more information about this option, see [`set_ttl_v4`]. /// - /// [`set_ttl`]: Socket::set_ttl - pub fn ttl(&self) -> io::Result { + /// [`set_ttl_v4`]: Socket::set_ttl_v4 + pub fn ttl_v4(&self) -> io::Result { unsafe { getsockopt::(self.as_raw(), sys::IPPROTO_IP, sys::IP_TTL).map(|ttl| ttl as u32) } @@ -1512,7 +1515,7 @@ impl Socket { /// /// This value sets the time-to-live field that is used in every packet sent /// from this socket. - pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { + pub fn set_ttl_v4(&self, ttl: u32) -> io::Result<()> { unsafe { setsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_TTL, ttl as c_int) } } @@ -1530,18 +1533,18 @@ impl Socket { target_os = "illumos", target_os = "haiku", )))] - pub fn set_tos(&self, tos: u32) -> io::Result<()> { + pub fn set_tos_v4(&self, tos: u32) -> io::Result<()> { unsafe { setsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_TOS, tos as c_int) } } /// Get the value of the `IP_TOS` option for this socket. /// - /// For more information about this option, see [`set_tos`]. + /// For more information about this option, see [`set_tos_v4`]. /// /// NOTE: /// documents that not all versions of windows support `IP_TOS`. /// - /// [`set_tos`]: Socket::set_tos + /// [`set_tos_v4`]: Socket::set_tos_v4 #[cfg(not(any( target_os = "fuchsia", target_os = "redox", @@ -1549,7 +1552,7 @@ impl Socket { target_os = "illumos", target_os = "haiku", )))] - pub fn tos(&self) -> io::Result { + pub fn tos_v4(&self) -> io::Result { unsafe { getsockopt::(self.as_raw(), sys::IPPROTO_IP, sys::IP_TOS).map(|tos| tos as u32) } @@ -1575,7 +1578,7 @@ impl Socket { target_os = "espidf", target_os = "vita", )))] - pub fn set_recv_tos(&self, recv_tos: bool) -> io::Result<()> { + pub fn set_recv_tos_v4(&self, recv_tos: bool) -> io::Result<()> { unsafe { setsockopt( self.as_raw(), @@ -1588,9 +1591,9 @@ impl Socket { /// Get the value of the `IP_RECVTOS` option for this socket. /// - /// For more information about this option, see [`set_recv_tos`]. + /// For more information about this option, see [`set_recv_tos_v4`]. /// - /// [`set_recv_tos`]: Socket::set_recv_tos + /// [`set_recv_tos_v4`]: Socket::set_recv_tos_v4 #[cfg(not(any( target_os = "aix", target_os = "dragonfly", @@ -1606,7 +1609,7 @@ impl Socket { target_os = "espidf", target_os = "vita", )))] - pub fn recv_tos(&self) -> io::Result { + pub fn recv_tos_v4(&self) -> io::Result { unsafe { getsockopt::(self.as_raw(), sys::IPPROTO_IP, sys::IP_RECVTOS) .map(|recv_tos| recv_tos > 0) @@ -1620,6 +1623,66 @@ impl Socket { /// * Linux: /// * Windows: impl Socket { + /// Get the value of the `IP_HDRINCL` option on this socket. + /// + /// For more information about this option, see [`set_header_included_v6`]. + /// + /// [`set_header_included_v6`]: Socket::set_header_included_v6 + #[cfg(all( + feature = "all", + not(any( + target_os = "redox", + target_os = "espidf", + target_os = "openbsd", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "netbsd" + )) + ))] + pub fn header_included_v6(&self) -> io::Result { + unsafe { + getsockopt::(self.as_raw(), sys::IPPROTO_IPV6, sys::IP_HDRINCL) + .map(|included| included != 0) + } + } + + /// Set the value of the `IP_HDRINCL` option on this socket. + /// + /// If enabled, the user supplies an IP header in front of the user data. + /// Valid only for [`SOCK_RAW`] sockets; see [raw(7)] for more information. + /// When this flag is enabled, the values set by `IP_OPTIONS` are ignored. + /// + /// [`SOCK_RAW`]: Type::RAW + /// [raw(7)]: https://man7.org/linux/man-pages/man7/raw.7.html + #[cfg_attr( + any(target_os = "fuchsia", target_os = "illumos", target_os = "solaris"), + allow(rustdoc::broken_intra_doc_links) + )] + #[cfg(all( + feature = "all", + not(any( + target_os = "redox", + target_os = "espidf", + target_os = "openbsd", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "netbsd" + )) + ))] + pub fn set_header_included_v6(&self, included: bool) -> io::Result<()> { + unsafe { + setsockopt( + self.as_raw(), + sys::IPPROTO_IPV6, + #[cfg(target_os = "linux")] + sys::IPV6_HDRINCL, + #[cfg(not(target_os = "linux"))] + sys::IP_HDRINCL, + included as c_int, + ) + } + } + /// Join a multicast group using `IPV6_ADD_MEMBERSHIP` option on this socket. /// /// Some OSs use `IPV6_JOIN_GROUP` for this option. @@ -1702,7 +1765,6 @@ impl Socket { /// /// [`set_multicast_all_v6`]: Socket::set_multicast_all_v6 #[cfg(all(feature = "all", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))] pub fn multicast_all_v6(&self) -> io::Result { unsafe { getsockopt::(self.as_raw(), sys::IPPROTO_IPV6, libc::IPV6_MULTICAST_ALL) @@ -1721,7 +1783,6 @@ impl Socket { /// joined (for example via the `IPV6_ADD_MEMBERSHIP` option) on /// this particular socket. #[cfg(all(feature = "all", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))] pub fn set_multicast_all_v6(&self, all: bool) -> io::Result<()> { unsafe { setsockopt( @@ -1896,6 +1957,67 @@ impl Socket { ) } } + + /// Get the value of the `IPV6_RECVHOPLIMIT` option for this socket. + /// + /// For more information about this option, see [`set_recv_hoplimit_v6`]. + /// + /// [`set_recv_hoplimit_v6`]: Socket::set_recv_hoplimit_v6 + #[cfg(all( + feature = "all", + not(any( + windows, + target_os = "dragonfly", + target_os = "fuchsia", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox", + target_os = "solaris", + target_os = "haiku", + target_os = "hurd", + target_os = "espidf", + target_os = "vita", + )) + ))] + pub fn recv_hoplimit_v6(&self) -> io::Result { + unsafe { + getsockopt::(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_RECVHOPLIMIT) + .map(|recv_hoplimit| recv_hoplimit > 0) + } + } + /// Set the value of the `IPV6_RECVHOPLIMIT` option for this socket. + /// + /// The received hop limit is returned as ancillary data by recvmsg() + /// only if the application has enabled the IPV6_RECVHOPLIMIT socket + /// option: + #[cfg(all( + feature = "all", + not(any( + windows, + target_os = "dragonfly", + target_os = "fuchsia", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox", + target_os = "solaris", + target_os = "haiku", + target_os = "hurd", + target_os = "espidf", + target_os = "vita", + )) + ))] + pub fn set_recv_hoplimit_v6(&self, recv_hoplimit: bool) -> io::Result<()> { + unsafe { + setsockopt( + self.as_raw(), + sys::IPPROTO_IPV6, + sys::IPV6_RECVHOPLIMIT, + recv_hoplimit as c_int, + ) + } + } } /// Socket options for TCP sockets, get/set using `IPPROTO_TCP`. @@ -1917,18 +2039,6 @@ impl Socket { target_os = "vita" )) ))] - #[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - not(any( - windows, - target_os = "haiku", - target_os = "openbsd", - target_os = "vita" - )) - ))) - )] pub fn keepalive_time(&self) -> io::Result { sys::keepalive_time(self.as_raw()) } @@ -1947,6 +2057,7 @@ impl Socket { target_os = "fuchsia", target_os = "illumos", target_os = "ios", + target_os = "visionos", target_os = "linux", target_os = "macos", target_os = "netbsd", @@ -1954,25 +2065,6 @@ impl Socket { target_os = "watchos", ) ))] - #[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "illumos", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "tvos", - target_os = "watchos", - ) - ))) - )] pub fn keepalive_interval(&self) -> io::Result { unsafe { getsockopt::(self.as_raw(), sys::IPPROTO_TCP, sys::TCP_KEEPINTVL) @@ -1994,6 +2086,7 @@ impl Socket { target_os = "fuchsia", target_os = "illumos", target_os = "ios", + target_os = "visionos", target_os = "linux", target_os = "macos", target_os = "netbsd", @@ -2001,25 +2094,6 @@ impl Socket { target_os = "watchos", ) ))] - #[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "illumos", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "tvos", - target_os = "watchos", - ) - ))) - )] pub fn keepalive_retries(&self) -> io::Result { unsafe { getsockopt::(self.as_raw(), sys::IPPROTO_TCP, sys::TCP_KEEPCNT) @@ -2099,6 +2173,29 @@ impl Socket { ) } } + + /// Get the value for the `SO_ORIGINAL_DST` option on this socket. + #[cfg(all( + feature = "all", + any( + target_os = "android", + target_os = "fuchsia", + target_os = "linux", + target_os = "windows", + ) + ))] + pub fn original_dst(&self) -> io::Result { + sys::original_dst(self.as_raw()) + } + + /// Get the value for the `IP6T_SO_ORIGINAL_DST` option on this socket. + #[cfg(all( + feature = "all", + any(target_os = "android", target_os = "linux", target_os = "windows") + ))] + pub fn original_dst_ipv6(&self) -> io::Result { + sys::original_dst_ipv6(self.as_raw()) + } } impl Read for Socket { @@ -2112,7 +2209,7 @@ impl Read for Socket { #[cfg(not(target_os = "redox"))] fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { // Safety: both `IoSliceMut` and `MaybeUninitSlice` promise to have the - // same layout, that of `iovec`/`WSABUF`. Furthermore `recv_vectored` + // same layout, that of `iovec`/`WSABUF`. Furthermore, `recv_vectored` // promises to not write unitialised bytes to the `bufs` and pass it // directly to the `recvmsg` system call, so this is safe. let bufs = unsafe { &mut *(bufs as *mut [IoSliceMut<'_>] as *mut [MaybeUninitSlice<'_>]) }; diff --git a/src/sockref.rs b/src/sockref.rs index d23b7c0f..59353b15 100644 --- a/src/sockref.rs +++ b/src/sockref.rs @@ -20,7 +20,7 @@ use crate::Socket; /// /// [`TcpStream`]: std::net::TcpStream // Don't use intra-doc links because they won't build on every platform. -/// [`AsFd`]: https://doc.rust-lang.org/stable/std/os/unix/io/trait.AsFd.html +/// [`AsFd`]: https://doc.rust-lang.org/stable/std/os/fd/trait.AsFd.html /// [`AsSocket`]: https://doc.rust-lang.org/stable/std/os/windows/io/trait.AsSocket.html /// /// # Examples @@ -78,7 +78,6 @@ impl<'s> Deref for SockRef<'s> { /// On Windows, a corresponding `From<&impl AsSocket>` implementation exists. #[cfg(unix)] -#[cfg_attr(docsrs, doc(cfg(unix)))] impl<'s, S> From<&'s S> for SockRef<'s> where S: AsFd, @@ -96,7 +95,6 @@ where /// On Unix, a corresponding `From<&impl AsFd>` implementation exists. #[cfg(windows)] -#[cfg_attr(docsrs, doc(cfg(windows)))] impl<'s, S> From<&'s S> for SockRef<'s> where S: AsSocket, diff --git a/src/sys/unix.rs b/src/sys/unix.rs index 805b6d55..8e24f4e5 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -18,9 +18,12 @@ use std::net::{Ipv4Addr, Ipv6Addr}; feature = "all", any( target_os = "ios", + target_os = "visionos", target_os = "macos", target_os = "tvos", target_os = "watchos", + target_os = "illumos", + target_os = "solaris", ) ))] use std::num::NonZeroU32; @@ -31,6 +34,7 @@ use std::num::NonZeroU32; target_os = "android", target_os = "freebsd", target_os = "ios", + target_os = "visionos", target_os = "linux", target_os = "macos", target_os = "tvos", @@ -46,6 +50,7 @@ use std::os::unix::ffi::OsStrExt; target_os = "android", target_os = "freebsd", target_os = "ios", + target_os = "visionos", target_os = "linux", target_os = "macos", target_os = "tvos", @@ -63,6 +68,7 @@ use std::{io, slice}; #[cfg(not(any( target_os = "ios", + target_os = "visionos", target_os = "macos", target_os = "tvos", target_os = "watchos", @@ -118,6 +124,25 @@ pub(crate) use libc::SO_OOBINLINE; // Used in `Socket`. #[cfg(not(target_os = "nto"))] pub(crate) use libc::ipv6_mreq as Ipv6Mreq; +#[cfg(all(feature = "all", target_os = "linux"))] +pub(crate) use libc::IPV6_HDRINCL; +#[cfg(all( + feature = "all", + not(any( + target_os = "dragonfly", + target_os = "fuchsia", + target_os = "hurd", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox", + target_os = "solaris", + target_os = "haiku", + target_os = "espidf", + target_os = "vita", + )) +))] +pub(crate) use libc::IPV6_RECVHOPLIMIT; #[cfg(not(any( target_os = "dragonfly", target_os = "fuchsia", @@ -160,6 +185,7 @@ pub(crate) use libc::IP_RECVTOS; pub(crate) use libc::IP_TOS; #[cfg(not(any( target_os = "ios", + target_os = "visionos", target_os = "macos", target_os = "tvos", target_os = "watchos", @@ -167,11 +193,14 @@ pub(crate) use libc::IP_TOS; pub(crate) use libc::SO_LINGER; #[cfg(any( target_os = "ios", + target_os = "visionos", target_os = "macos", target_os = "tvos", target_os = "watchos", ))] pub(crate) use libc::SO_LINGER_SEC as SO_LINGER; +#[cfg(target_os = "linux")] +pub(crate) use libc::SO_PASSCRED; pub(crate) use libc::{ ip_mreq as IpMreq, linger, IPPROTO_IP, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, IPV6_MULTICAST_IF, IPV6_MULTICAST_LOOP, IPV6_UNICAST_HOPS, IPV6_V6ONLY, IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP, @@ -200,6 +229,7 @@ pub(crate) use libc::{ target_os = "haiku", target_os = "illumos", target_os = "ios", + target_os = "visionos", target_os = "macos", target_os = "netbsd", target_os = "nto", @@ -215,6 +245,7 @@ pub(crate) use libc::{IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP}; target_os = "haiku", target_os = "illumos", target_os = "ios", + target_os = "visionos", target_os = "macos", target_os = "netbsd", target_os = "openbsd", @@ -234,6 +265,7 @@ pub(crate) use libc::{ target_os = "fuchsia", target_os = "illumos", target_os = "ios", + target_os = "visionos", target_os = "linux", target_os = "macos", target_os = "netbsd", @@ -248,6 +280,7 @@ pub(crate) type Bool = c_int; #[cfg(any( target_os = "ios", + target_os = "visionos", target_os = "macos", target_os = "nto", target_os = "tvos", @@ -257,6 +290,7 @@ use libc::TCP_KEEPALIVE as KEEPALIVE_TIME; #[cfg(not(any( target_os = "haiku", target_os = "ios", + target_os = "visionos", target_os = "macos", target_os = "nto", target_os = "openbsd", @@ -282,6 +316,7 @@ macro_rules! syscall { /// Maximum size of a buffer passed to system call like `recv` and `send`. #[cfg(not(any( target_os = "ios", + target_os = "visionos", target_os = "macos", target_os = "tvos", target_os = "watchos", @@ -298,6 +333,7 @@ const MAX_BUF_LEN: usize = ssize_t::MAX as usize; // both platforms. #[cfg(any( target_os = "ios", + target_os = "visionos", target_os = "macos", target_os = "tvos", target_os = "watchos", @@ -337,6 +373,7 @@ type IovLen = usize; target_os = "hurd", target_os = "illumos", target_os = "ios", + target_os = "visionos", target_os = "macos", target_os = "netbsd", target_os = "nto", @@ -356,21 +393,10 @@ impl Domain { feature = "all", any(target_os = "android", target_os = "fuchsia", target_os = "linux") ))] - #[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - any(target_os = "android", target_os = "fuchsia", target_os = "linux") - ))) - )] pub const PACKET: Domain = Domain(libc::AF_PACKET); /// Domain for low-level VSOCK interface, corresponding to `AF_VSOCK`. #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))] - #[cfg_attr( - docsrs, - doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))) - )] pub const VSOCK: Domain = Domain(libc::AF_VSOCK); } @@ -380,13 +406,8 @@ impl_debug!( libc::AF_INET6, libc::AF_UNIX, #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] - #[cfg_attr( - docsrs, - doc(cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))) - )] libc::AF_PACKET, #[cfg(any(target_os = "android", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(any(target_os = "android", target_os = "linux"))))] libc::AF_VSOCK, libc::AF_UNSPEC, // = 0. ); @@ -407,22 +428,6 @@ impl Type { target_os = "openbsd" ) ))] - #[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd" - ) - ))) - )] pub const fn nonblocking(self) -> Type { Type(self.0 | libc::SOCK_NONBLOCK) } @@ -444,25 +449,6 @@ impl Type { target_os = "solaris", ) ))] - #[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "hurd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - target_os = "redox", - target_os = "solaris", - ) - ))) - )] pub const fn cloexec(self) -> Type { self._cloexec() } @@ -573,6 +559,29 @@ impl RecvFlags { pub const fn is_out_of_band(self) -> bool { self.0 & libc::MSG_OOB != 0 } + + /// Check if the confirm flag is set. + /// + /// This is used by SocketCAN to indicate a frame was sent via the + /// socket it is received on. This flag can be interpreted as a + /// 'transmission confirmation'. + /// + /// On Unix this corresponds to the `MSG_CONFIRM` flag. + #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))] + pub const fn is_confirm(self) -> bool { + self.0 & libc::MSG_CONFIRM != 0 + } + + /// Check if the don't route flag is set. + /// + /// This is used by SocketCAN to indicate a frame was created + /// on the local host. + /// + /// On Unix this corresponds to the `MSG_DONTROUTE` flag. + #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))] + pub const fn is_dontroute(self) -> bool { + self.0 & libc::MSG_DONTROUTE != 0 + } } #[cfg(not(target_os = "redox"))] @@ -584,6 +593,10 @@ impl std::fmt::Debug for RecvFlags { s.field("is_out_of_band", &self.is_out_of_band()); #[cfg(not(target_os = "espidf"))] s.field("is_truncated", &self.is_truncated()); + #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))] + s.field("is_confirm", &self.is_confirm()); + #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))] + s.field("is_dontroute", &self.is_dontroute()); s.finish() } } @@ -703,6 +716,11 @@ pub(crate) fn msghdr_flags(msg: &msghdr) -> RecvFlags { RecvFlags(msg.msg_flags) } +#[cfg(not(target_os = "redox"))] +pub(crate) fn msghdr_control_len(msg: &msghdr) -> usize { + msg.msg_controllen as _ +} + /// Unix only API. impl SockAddr { /// Constructs a `SockAddr` with the family `AF_VSOCK` and the provided CID/port. @@ -713,10 +731,6 @@ impl SockAddr { /// infallible. #[allow(unsafe_op_in_unsafe_fn)] #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))] - #[cfg_attr( - docsrs, - doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))) - )] pub fn vsock(cid: u32, port: u32) -> SockAddr { // SAFETY: a `sockaddr_storage` of all zeros is valid. let mut storage = unsafe { mem::zeroed::() }; @@ -733,10 +747,6 @@ impl SockAddr { /// Returns this address VSOCK CID/port if it is in the `AF_VSOCK` family, /// otherwise return `None`. #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))] - #[cfg_attr( - docsrs, - doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))) - )] pub fn as_vsock_address(&self) -> Option<(u32, u32)> { if self.family() == libc::AF_VSOCK as sa_family_t { // Safety: if the ss_family field is AF_VSOCK then storage must be a sockaddr_vm. @@ -861,7 +871,6 @@ pub(crate) fn socket(family: c_int, ty: c_int, protocol: c_int) -> io::Result io::Result<[Socket; 2]> { let mut fds = [0, 0]; syscall!(socketpair(family, ty, protocol, fds.as_mut_ptr())).map(|_| fds) @@ -1156,13 +1165,6 @@ fn into_timeval(duration: Option) -> libc::timeval { feature = "all", not(any(target_os = "haiku", target_os = "openbsd", target_os = "vita")) ))] -#[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - not(any(target_os = "haiku", target_os = "openbsd", target_os = "vita")) - ))) -)] pub(crate) fn keepalive_time(fd: Socket) -> io::Result { unsafe { getsockopt::(fd, IPPROTO_TCP, KEEPALIVE_TIME) @@ -1192,6 +1194,7 @@ pub(crate) fn set_tcp_keepalive(fd: Socket, keepalive: &TcpKeepalive) -> io::Res target_os = "hurd", target_os = "illumos", target_os = "ios", + target_os = "visionos", target_os = "linux", target_os = "macos", target_os = "netbsd", @@ -1349,6 +1352,47 @@ pub(crate) const fn to_mreqn( } } +#[cfg(all( + feature = "all", + any(target_os = "android", target_os = "fuchsia", target_os = "linux") +))] +pub(crate) fn original_dst(fd: Socket) -> io::Result { + // Safety: `getsockopt` initialises the `SockAddr` for us. + unsafe { + SockAddr::try_init(|storage, len| { + syscall!(getsockopt( + fd, + libc::SOL_IP, + libc::SO_ORIGINAL_DST, + storage.cast(), + len + )) + }) + } + .map(|(_, addr)| addr) +} + +/// Get the value for the `IP6T_SO_ORIGINAL_DST` option on this socket. +/// +/// This value contains the original destination IPv6 address of the connection +/// redirected using `ip6tables` `REDIRECT` or `TPROXY`. +#[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))] +pub(crate) fn original_dst_ipv6(fd: Socket) -> io::Result { + // Safety: `getsockopt` initialises the `SockAddr` for us. + unsafe { + SockAddr::try_init(|storage, len| { + syscall!(getsockopt( + fd, + libc::SOL_IPV6, + libc::IP6T_SO_ORIGINAL_DST, + storage.cast(), + len + )) + }) + } + .map(|(_, addr)| addr) +} + /// Unix only API. impl crate::Socket { /// Accept a new incoming connection from this listener. @@ -1372,22 +1416,6 @@ impl crate::Socket { target_os = "openbsd", ) ))] - #[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - ) - ))) - )] pub fn accept4(&self, flags: c_int) -> io::Result<(crate::Socket, SockAddr)> { self._accept4(flags) } @@ -1420,6 +1448,7 @@ impl crate::Socket { #[cfg_attr( any( target_os = "ios", + target_os = "visionos", target_os = "macos", target_os = "tvos", target_os = "watchos" @@ -1427,7 +1456,6 @@ impl crate::Socket { allow(rustdoc::broken_intra_doc_links) )] #[cfg(all(feature = "all", not(target_os = "vita")))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "all", unix))))] pub fn set_cloexec(&self, close_on_exec: bool) -> io::Result<()> { self._set_cloexec(close_on_exec) } @@ -1456,29 +1484,19 @@ impl crate::Socket { feature = "all", any( target_os = "ios", + target_os = "visionos", target_os = "macos", target_os = "tvos", target_os = "watchos", ) ))] - #[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - any( - target_os = "ios", - target_os = "macos", - target_os = "tvos", - target_os = "watchos", - ) - ))) - )] pub fn set_nosigpipe(&self, nosigpipe: bool) -> io::Result<()> { self._set_nosigpipe(nosigpipe) } #[cfg(any( target_os = "ios", + target_os = "visionos", target_os = "macos", target_os = "tvos", target_os = "watchos", @@ -1500,7 +1518,6 @@ impl crate::Socket { /// /// [`set_mss`]: crate::Socket::set_mss #[cfg(all(feature = "all", not(target_os = "redox")))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "all", unix, not(target_os = "redox")))))] pub fn mss(&self) -> io::Result { unsafe { getsockopt::(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_MAXSEG) @@ -1513,7 +1530,6 @@ impl crate::Socket { /// The `TCP_MAXSEG` option denotes the TCP Maximum Segment Size and is only /// available on TCP sockets. #[cfg(all(feature = "all", not(target_os = "redox")))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "all", unix, not(target_os = "redox")))))] pub fn set_mss(&self, mss: u32) -> io::Result<()> { unsafe { setsockopt( @@ -1537,19 +1553,6 @@ impl crate::Socket { target_os = "linux", ) ))] - #[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - any( - target_os = "aix", - target_os = "android", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "linux", - ) - ))) - )] pub fn is_listener(&self) -> io::Result { unsafe { getsockopt::(self.as_raw(), libc::SOL_SOCKET, libc::SO_ACCEPTCONN) @@ -1569,16 +1572,6 @@ impl crate::Socket { target_os = "linux", ) ))] - #[cfg_attr(docsrs, doc(cfg(all( - feature = "all", - any( - target_os = "android", - // TODO: add FreeBSD. - // target_os = "freebsd", - target_os = "fuchsia", - target_os = "linux", - ) - ))))] pub fn domain(&self) -> io::Result { unsafe { getsockopt::(self.as_raw(), libc::SOL_SOCKET, libc::SO_DOMAIN).map(Domain) } } @@ -1594,18 +1587,6 @@ impl crate::Socket { target_os = "linux", ) ))] - #[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - any( - target_os = "android", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "linux", - ) - ))) - )] pub fn protocol(&self) -> io::Result> { unsafe { getsockopt::(self.as_raw(), libc::SOL_SOCKET, libc::SO_PROTOCOL).map(|v| match v @@ -1626,13 +1607,6 @@ impl crate::Socket { feature = "all", any(target_os = "android", target_os = "fuchsia", target_os = "linux") ))] - #[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - any(target_os = "android", target_os = "fuchsia", target_os = "linux") - ))) - )] pub fn mark(&self) -> io::Result { unsafe { getsockopt::(self.as_raw(), libc::SOL_SOCKET, libc::SO_MARK) @@ -1651,13 +1625,6 @@ impl crate::Socket { feature = "all", any(target_os = "android", target_os = "fuchsia", target_os = "linux") ))] - #[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - any(target_os = "android", target_os = "fuchsia", target_os = "linux") - ))) - )] pub fn set_mark(&self, mark: u32) -> io::Result<()> { unsafe { setsockopt::( @@ -1678,13 +1645,6 @@ impl crate::Socket { feature = "all", any(target_os = "android", target_os = "fuchsia", target_os = "linux") ))] - #[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - any(target_os = "android", target_os = "fuchsia", target_os = "linux") - ))) - )] pub fn cork(&self) -> io::Result { unsafe { getsockopt::(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_CORK) @@ -1702,13 +1662,6 @@ impl crate::Socket { feature = "all", any(target_os = "android", target_os = "fuchsia", target_os = "linux") ))] - #[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - any(target_os = "android", target_os = "fuchsia", target_os = "linux") - ))) - )] pub fn set_cork(&self, cork: bool) -> io::Result<()> { unsafe { setsockopt( @@ -1729,13 +1682,6 @@ impl crate::Socket { feature = "all", any(target_os = "android", target_os = "fuchsia", target_os = "linux") ))] - #[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - any(target_os = "android", target_os = "fuchsia", target_os = "linux") - ))) - )] pub fn quickack(&self) -> io::Result { unsafe { getsockopt::(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_QUICKACK) @@ -1753,13 +1699,6 @@ impl crate::Socket { feature = "all", any(target_os = "android", target_os = "fuchsia", target_os = "linux") ))] - #[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - any(target_os = "android", target_os = "fuchsia", target_os = "linux") - ))) - )] pub fn set_quickack(&self, quickack: bool) -> io::Result<()> { unsafe { setsockopt( @@ -1780,13 +1719,6 @@ impl crate::Socket { feature = "all", any(target_os = "android", target_os = "fuchsia", target_os = "linux") ))] - #[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - any(target_os = "android", target_os = "fuchsia", target_os = "linux") - ))) - )] pub fn thin_linear_timeouts(&self) -> io::Result { unsafe { getsockopt::( @@ -1807,13 +1739,6 @@ impl crate::Socket { feature = "all", any(target_os = "android", target_os = "fuchsia", target_os = "linux") ))] - #[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - any(target_os = "android", target_os = "fuchsia", target_os = "linux") - ))) - )] pub fn set_thin_linear_timeouts(&self, timeouts: bool) -> io::Result<()> { unsafe { setsockopt( @@ -1832,13 +1757,6 @@ impl crate::Socket { feature = "all", any(target_os = "android", target_os = "fuchsia", target_os = "linux") ))] - #[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - any(target_os = "android", target_os = "fuchsia", target_os = "linux") - ))) - )] pub fn device(&self) -> io::Result>> { // TODO: replace with `MaybeUninit::uninit_array` once stable. let mut buf: [MaybeUninit; libc::IFNAMSIZ] = @@ -1871,13 +1789,6 @@ impl crate::Socket { feature = "all", any(target_os = "android", target_os = "fuchsia", target_os = "linux") ))] - #[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - any(target_os = "android", target_os = "fuchsia", target_os = "linux") - ))) - )] pub fn bind_device(&self, interface: Option<&[u8]>) -> io::Result<()> { let (value, len) = if let Some(interface) = interface { (interface.as_ptr(), interface.len()) @@ -1898,7 +1809,6 @@ impl crate::Socket { /// /// Bind socket to the specified forwarding table (VRF) on a FreeBSD. #[cfg(all(feature = "all", target_os = "freebsd"))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "freebsd"))))] pub fn set_fib(&self, fib: u32) -> io::Result<()> { syscall!(setsockopt( self.as_raw(), @@ -1910,33 +1820,6 @@ impl crate::Socket { .map(|_| ()) } - /// This method is deprecated, use [`crate::Socket::bind_device_by_index_v4`]. - #[cfg(all( - feature = "all", - any( - target_os = "ios", - target_os = "macos", - target_os = "tvos", - target_os = "watchos", - ) - ))] - #[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - any( - target_os = "ios", - target_os = "macos", - target_os = "tvos", - target_os = "watchos", - ) - ))) - )] - #[deprecated = "Use `Socket::bind_device_by_index_v4` instead"] - pub fn bind_device_by_index(&self, interface: Option) -> io::Result<()> { - self.bind_device_by_index_v4(interface) - } - /// Sets the value for `IP_BOUND_IF` option on this socket. /// /// If a socket is bound to an interface, only packets received from that @@ -1951,23 +1834,14 @@ impl crate::Socket { feature = "all", any( target_os = "ios", + target_os = "visionos", target_os = "macos", target_os = "tvos", target_os = "watchos", + target_os = "illumos", + target_os = "solaris", ) ))] - #[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - any( - target_os = "ios", - target_os = "macos", - target_os = "tvos", - target_os = "watchos", - ) - ))) - )] pub fn bind_device_by_index_v4(&self, interface: Option) -> io::Result<()> { let index = interface.map_or(0, NonZeroU32::get); unsafe { setsockopt(self.as_raw(), IPPROTO_IP, libc::IP_BOUND_IF, index) } @@ -1987,23 +1861,14 @@ impl crate::Socket { feature = "all", any( target_os = "ios", + target_os = "visionos", target_os = "macos", target_os = "tvos", target_os = "watchos", + target_os = "illumos", + target_os = "solaris", ) ))] - #[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - any( - target_os = "ios", - target_os = "macos", - target_os = "tvos", - target_os = "watchos", - ) - ))) - )] pub fn bind_device_by_index_v6(&self, interface: Option) -> io::Result<()> { let index = interface.map_or(0, NonZeroU32::get); unsafe { setsockopt(self.as_raw(), IPPROTO_IPV6, libc::IPV6_BOUND_IF, index) } @@ -2018,56 +1883,20 @@ impl crate::Socket { feature = "all", any( target_os = "ios", + target_os = "visionos", target_os = "macos", target_os = "tvos", target_os = "watchos", + target_os = "illumos", + target_os = "solaris", ) ))] - #[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - any( - target_os = "ios", - target_os = "macos", - target_os = "tvos", - target_os = "watchos", - ) - ))) - )] pub fn device_index_v4(&self) -> io::Result> { let index = unsafe { getsockopt::(self.as_raw(), IPPROTO_IP, libc::IP_BOUND_IF)? }; Ok(NonZeroU32::new(index)) } - /// This method is deprecated, use [`crate::Socket::device_index_v4`]. - #[cfg(all( - feature = "all", - any( - target_os = "ios", - target_os = "macos", - target_os = "tvos", - target_os = "watchos", - ) - ))] - #[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - any( - target_os = "ios", - target_os = "macos", - target_os = "tvos", - target_os = "watchos", - ) - ))) - )] - #[deprecated = "Use `Socket::device_index_v4` instead"] - pub fn device_index(&self) -> io::Result> { - self.device_index_v4() - } - /// Gets the value for `IPV6_BOUND_IF` option on this socket, i.e. the index /// for the interface to which the socket is bound. /// @@ -2077,23 +1906,14 @@ impl crate::Socket { feature = "all", any( target_os = "ios", + target_os = "visionos", target_os = "macos", target_os = "tvos", target_os = "watchos", + target_os = "illumos", + target_os = "solaris", ) ))] - #[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - any( - target_os = "ios", - target_os = "macos", - target_os = "tvos", - target_os = "watchos", - ) - ))) - )] pub fn device_index_v6(&self) -> io::Result> { let index = unsafe { getsockopt::(self.as_raw(), IPPROTO_IPV6, libc::IPV6_BOUND_IF)? @@ -2107,7 +1927,6 @@ impl crate::Socket { /// /// [`set_cpu_affinity`]: crate::Socket::set_cpu_affinity #[cfg(all(feature = "all", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))] pub fn cpu_affinity(&self) -> io::Result { unsafe { getsockopt::(self.as_raw(), libc::SOL_SOCKET, libc::SO_INCOMING_CPU) @@ -2119,7 +1938,6 @@ impl crate::Socket { /// /// Sets the CPU affinity of the socket. #[cfg(all(feature = "all", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))] pub fn set_cpu_affinity(&self, cpu: usize) -> io::Result<()> { unsafe { setsockopt( @@ -2140,14 +1958,6 @@ impl crate::Socket { feature = "all", not(any(target_os = "solaris", target_os = "illumos")) ))] - #[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - unix, - not(any(target_os = "solaris", target_os = "illumos")) - ))) - )] pub fn reuse_port(&self) -> io::Result { unsafe { getsockopt::(self.as_raw(), libc::SOL_SOCKET, libc::SO_REUSEPORT) @@ -2164,14 +1974,6 @@ impl crate::Socket { feature = "all", not(any(target_os = "solaris", target_os = "illumos")) ))] - #[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - unix, - not(any(target_os = "solaris", target_os = "illumos")) - ))) - )] pub fn set_reuse_port(&self, reuse: bool) -> io::Result<()> { unsafe { setsockopt( @@ -2221,13 +2023,6 @@ impl crate::Socket { feature = "all", any(target_os = "android", target_os = "fuchsia", target_os = "linux") ))] - #[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - any(target_os = "android", target_os = "fuchsia", target_os = "linux") - ))) - )] pub fn freebind(&self) -> io::Result { unsafe { getsockopt::(self.as_raw(), libc::SOL_IP, libc::IP_FREEBIND) @@ -2246,13 +2041,6 @@ impl crate::Socket { feature = "all", any(target_os = "android", target_os = "fuchsia", target_os = "linux") ))] - #[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - any(target_os = "android", target_os = "fuchsia", target_os = "linux") - ))) - )] pub fn set_freebind(&self, freebind: bool) -> io::Result<()> { unsafe { setsockopt( @@ -2272,10 +2060,6 @@ impl crate::Socket { /// /// [`set_freebind`]: crate::Socket::set_freebind #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))] - #[cfg_attr( - docsrs, - doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))) - )] pub fn freebind_ipv6(&self) -> io::Result { unsafe { getsockopt::(self.as_raw(), libc::SOL_IPV6, libc::IPV6_FREEBIND) @@ -2314,10 +2098,6 @@ impl crate::Socket { /// # } /// ``` #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))] - #[cfg_attr( - docsrs, - doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))) - )] pub fn set_freebind_ipv6(&self, freebind: bool) -> io::Result<()> { unsafe { setsockopt( @@ -2329,62 +2109,6 @@ impl crate::Socket { } } - /// Get the value for the `SO_ORIGINAL_DST` option on this socket. - /// - /// This value contains the original destination IPv4 address of the connection - /// redirected using `iptables` `REDIRECT` or `TPROXY`. - #[cfg(all( - feature = "all", - any(target_os = "android", target_os = "fuchsia", target_os = "linux") - ))] - #[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - any(target_os = "android", target_os = "fuchsia", target_os = "linux") - ))) - )] - pub fn original_dst(&self) -> io::Result { - // Safety: `getsockopt` initialises the `SockAddr` for us. - unsafe { - SockAddr::try_init(|storage, len| { - syscall!(getsockopt( - self.as_raw(), - libc::SOL_IP, - libc::SO_ORIGINAL_DST, - storage.cast(), - len - )) - }) - } - .map(|(_, addr)| addr) - } - - /// Get the value for the `IP6T_SO_ORIGINAL_DST` option on this socket. - /// - /// This value contains the original destination IPv6 address of the connection - /// redirected using `ip6tables` `REDIRECT` or `TPROXY`. - #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))] - #[cfg_attr( - docsrs, - doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))) - )] - pub fn original_dst_ipv6(&self) -> io::Result { - // Safety: `getsockopt` initialises the `SockAddr` for us. - unsafe { - SockAddr::try_init(|storage, len| { - syscall!(getsockopt( - self.as_raw(), - libc::SOL_IPV6, - libc::IP6T_SO_ORIGINAL_DST, - storage.cast(), - len - )) - }) - } - .map(|(_, addr)| addr) - } - /// Copies data between a `file` and this socket using the `sendfile(2)` /// system call. Because this copying is done within the kernel, /// `sendfile()` is more efficient than the combination of `read(2)` and @@ -2411,28 +2135,13 @@ impl crate::Socket { target_os = "android", target_os = "freebsd", target_os = "ios", + target_os = "visionos", target_os = "linux", target_os = "macos", target_os = "tvos", target_os = "watchos", ) ))] - #[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - any( - target_os = "aix", - target_os = "android", - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "tvos", - target_os = "watchos", - ) - ))) - )] pub fn sendfile( &self, file: &F, @@ -2449,6 +2158,7 @@ impl crate::Socket { feature = "all", any( target_os = "ios", + target_os = "visionos", target_os = "macos", target_os = "tvos", target_os = "watchos", @@ -2564,13 +2274,6 @@ impl crate::Socket { feature = "all", any(target_os = "android", target_os = "fuchsia", target_os = "linux") ))] - #[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - any(target_os = "android", target_os = "fuchsia", target_os = "linux") - ))) - )] pub fn set_tcp_user_timeout(&self, timeout: Option) -> io::Result<()> { let timeout = timeout.map_or(0, |to| { min(to.as_millis(), libc::c_uint::MAX as u128) as libc::c_uint @@ -2594,13 +2297,6 @@ impl crate::Socket { feature = "all", any(target_os = "android", target_os = "fuchsia", target_os = "linux") ))] - #[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - any(target_os = "android", target_os = "fuchsia", target_os = "linux") - ))) - )] pub fn tcp_user_timeout(&self) -> io::Result> { unsafe { getsockopt::(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_USER_TIMEOUT) @@ -2654,7 +2350,6 @@ impl crate::Socket { /// /// For more information about this option, see [Linux patch](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=5daab9db7b65df87da26fd8cfa695fb9546a1ddb) #[cfg(all(feature = "all", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))] pub fn cookie(&self) -> io::Result { unsafe { getsockopt::(self.as_raw(), libc::SOL_SOCKET, libc::SO_COOKIE) } } @@ -2677,22 +2372,6 @@ impl crate::Socket { target_os = "openbsd" ) ))] - #[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ) - ))) - )] pub fn tclass_v6(&self) -> io::Result { unsafe { getsockopt::(self.as_raw(), IPPROTO_IPV6, libc::IPV6_TCLASS) @@ -2717,22 +2396,6 @@ impl crate::Socket { target_os = "openbsd" ) ))] - #[cfg_attr( - docsrs, - doc(cfg(all( - feature = "all", - any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" - ) - ))) - )] pub fn set_tclass_v6(&self, tclass: u32) -> io::Result<()> { unsafe { setsockopt( @@ -2750,10 +2413,6 @@ impl crate::Socket { /// /// [`set_tcp_congestion`]: crate::Socket::set_tcp_congestion #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))] - #[cfg_attr( - docsrs, - doc(cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))) - )] pub fn tcp_congestion(&self) -> io::Result> { let mut payload: [u8; TCP_CA_NAME_MAX] = [0; TCP_CA_NAME_MAX]; let mut len = payload.len() as libc::socklen_t; @@ -2774,10 +2433,6 @@ impl crate::Socket { /// The value must be a valid TCP congestion control algorithm name of the /// platform. For example, Linux may supports "reno", "cubic". #[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))] - #[cfg_attr( - docsrs, - doc(cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))) - )] pub fn set_tcp_congestion(&self, tcp_ca_name: &[u8]) -> io::Result<()> { syscall!(setsockopt( self.as_raw(), @@ -2800,7 +2455,6 @@ impl crate::Socket { /// [`connect`]: crate::Socket::connect /// [`bind`]: crate::Socket::bind #[cfg(all(feature = "all", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))] pub fn set_dccp_service(&self, code: u32) -> io::Result<()> { unsafe { setsockopt( @@ -2818,7 +2472,6 @@ impl crate::Socket { /// /// [`set_dccp_service`]: crate::Socket::set_dccp_service #[cfg(all(feature = "all", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))] pub fn dccp_service(&self) -> io::Result { unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_SERVICE) } } @@ -2827,7 +2480,6 @@ impl crate::Socket { /// /// This option sets both the TX and RX CCIDs at the same time. #[cfg(all(feature = "all", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))] pub fn set_dccp_ccid(&self, ccid: u8) -> io::Result<()> { unsafe { setsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_CCID, ccid) } } @@ -2838,7 +2490,6 @@ impl crate::Socket { /// /// [`set_dccp_ccid`]: crate::Socket::set_dccp_ccid #[cfg(all(feature = "all", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))] pub fn dccp_tx_ccid(&self) -> io::Result { unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_TX_CCID) } } @@ -2849,7 +2500,6 @@ impl crate::Socket { /// /// [`set_dccp_ccid`]: crate::Socket::set_dccp_ccid #[cfg(all(feature = "all", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))] pub fn dccp_xx_ccid(&self) -> io::Result { unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_RX_CCID) } } @@ -2859,7 +2509,6 @@ impl crate::Socket { /// Enables a listening socket to hold timewait state when closing the /// connection. This option must be set after `accept` returns. #[cfg(all(feature = "all", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))] pub fn set_dccp_server_timewait(&self, hold_timewait: bool) -> io::Result<()> { unsafe { setsockopt( @@ -2877,7 +2526,6 @@ impl crate::Socket { /// /// [`set_dccp_server_timewait`]: crate::Socket::set_dccp_server_timewait #[cfg(all(feature = "all", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))] pub fn dccp_server_timewait(&self) -> io::Result { unsafe { getsockopt( @@ -2896,7 +2544,6 @@ impl crate::Socket { /// accepted by the receiver. Hence, when using this feature on the sender, /// it must be enabled at the receiver too, with suitable choice of CsCov. #[cfg(all(feature = "all", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))] pub fn set_dccp_send_cscov(&self, level: u32) -> io::Result<()> { unsafe { setsockopt( @@ -2914,7 +2561,6 @@ impl crate::Socket { /// /// [`set_dccp_send_cscov`]: crate::Socket::set_dccp_send_cscov #[cfg(all(feature = "all", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))] pub fn dccp_send_cscov(&self) -> io::Result { unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_SEND_CSCOV) } } @@ -2925,7 +2571,6 @@ impl crate::Socket { /// /// [`set_dccp_send_cscov`]: crate::Socket::set_dccp_send_cscov #[cfg(all(feature = "all", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))] pub fn set_dccp_recv_cscov(&self, level: u32) -> io::Result<()> { unsafe { setsockopt( @@ -2943,7 +2588,6 @@ impl crate::Socket { /// /// [`set_dccp_recv_cscov`]: crate::Socket::set_dccp_recv_cscov #[cfg(all(feature = "all", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))] pub fn dccp_recv_cscov(&self) -> io::Result { unsafe { getsockopt(self.as_raw(), libc::SOL_DCCP, libc::DCCP_SOCKOPT_RECV_CSCOV) } } @@ -2953,7 +2597,6 @@ impl crate::Socket { /// This option sets the maximum length of the output queue. A zero value is /// interpreted as unbounded queue length. #[cfg(all(feature = "all", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))] pub fn set_dccp_qpolicy_txqlen(&self, length: u32) -> io::Result<()> { unsafe { setsockopt( @@ -2971,7 +2614,6 @@ impl crate::Socket { /// /// [`set_dccp_qpolicy_txqlen`]: crate::Socket::set_dccp_qpolicy_txqlen #[cfg(all(feature = "all", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))] pub fn dccp_qpolicy_txqlen(&self) -> io::Result { unsafe { getsockopt( @@ -2992,7 +2634,6 @@ impl crate::Socket { /// /// [documentation]: https://www.kernel.org/doc/html/latest/networking/dccp.html #[cfg(all(feature = "all", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))] pub fn dccp_available_ccids(&self) -> io::Result> { let mut endpoints = [0; N]; let mut length = endpoints.len() as libc::socklen_t; @@ -3011,7 +2652,6 @@ impl crate::Socket { /// This option retrieves the current maximum packet size (application /// payload size) in bytes. #[cfg(all(feature = "all", target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))] pub fn dccp_cur_mps(&self) -> io::Result { unsafe { getsockopt( @@ -3025,7 +2665,6 @@ impl crate::Socket { /// See [`Socket::dccp_available_ccids`]. #[cfg(all(feature = "all", target_os = "linux"))] -#[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))] #[derive(Debug)] pub struct CcidEndpoints { endpoints: [u8; N], @@ -3033,7 +2672,6 @@ pub struct CcidEndpoints { } #[cfg(all(feature = "all", target_os = "linux"))] -#[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))] impl std::ops::Deref for CcidEndpoints { type Target = [u8]; @@ -3042,7 +2680,6 @@ impl std::ops::Deref for CcidEndpoints { } } -#[cfg_attr(docsrs, doc(cfg(unix)))] impl AsFd for crate::Socket { fn as_fd(&self) -> BorrowedFd<'_> { // SAFETY: lifetime is bound by self. @@ -3050,14 +2687,12 @@ impl AsFd for crate::Socket { } } -#[cfg_attr(docsrs, doc(cfg(unix)))] impl AsRawFd for crate::Socket { fn as_raw_fd(&self) -> c_int { self.as_raw() } } -#[cfg_attr(docsrs, doc(cfg(unix)))] impl From for OwnedFd { fn from(sock: crate::Socket) -> OwnedFd { // SAFETY: sock.into_raw() always returns a valid fd. @@ -3065,14 +2700,12 @@ impl From for OwnedFd { } } -#[cfg_attr(docsrs, doc(cfg(unix)))] impl IntoRawFd for crate::Socket { fn into_raw_fd(self) -> c_int { self.into_raw() } } -#[cfg_attr(docsrs, doc(cfg(unix)))] impl From for crate::Socket { fn from(fd: OwnedFd) -> crate::Socket { // SAFETY: `OwnedFd` ensures the fd is valid. @@ -3080,7 +2713,6 @@ impl From for crate::Socket { } } -#[cfg_attr(docsrs, doc(cfg(unix)))] impl FromRawFd for crate::Socket { unsafe fn from_raw_fd(fd: c_int) -> crate::Socket { crate::Socket::from_raw(fd) diff --git a/src/sys/windows.rs b/src/sys/windows.rs index 4c5d9879..10852f19 100644 --- a/src/sys/windows.rs +++ b/src/sys/windows.rs @@ -20,14 +20,16 @@ use std::time::{Duration, Instant}; use std::{process, ptr, slice}; use windows_sys::Win32::Foundation::{SetHandleInformation, HANDLE, HANDLE_FLAG_INHERIT}; -#[cfg(feature = "all")] -use windows_sys::Win32::Networking::WinSock::SO_PROTOCOL_INFOW; use windows_sys::Win32::Networking::WinSock::{ self, tcp_keepalive, FIONBIO, IN6_ADDR, IN6_ADDR_0, INVALID_SOCKET, IN_ADDR, IN_ADDR_0, POLLERR, POLLHUP, POLLRDNORM, POLLWRNORM, SD_BOTH, SD_RECEIVE, SD_SEND, SIO_KEEPALIVE_VALS, SOCKET_ERROR, WSABUF, WSAEMSGSIZE, WSAESHUTDOWN, WSAPOLLFD, WSAPROTOCOL_INFOW, WSA_FLAG_NO_HANDLE_INHERIT, WSA_FLAG_OVERLAPPED, }; +#[cfg(feature = "all")] +use windows_sys::Win32::Networking::WinSock::{ + IP6T_SO_ORIGINAL_DST, SOL_IP, SO_ORIGINAL_DST, SO_PROTOCOL_INFOW, +}; use windows_sys::Win32::System::Threading::INFINITE; use crate::{MsgHdr, RecvFlags, SockAddr, TcpKeepalive, Type}; @@ -123,7 +125,6 @@ impl Type { /// Set `WSA_FLAG_NO_HANDLE_INHERIT` on the socket. #[cfg(feature = "all")] - #[cfg_attr(docsrs, doc(cfg(all(windows, feature = "all"))))] pub const fn no_inherit(self) -> Type { self._no_inherit() } @@ -215,6 +216,10 @@ pub(crate) fn msghdr_flags(msg: &msghdr) -> RecvFlags { RecvFlags(msg.dwFlags as c_int) } +pub(crate) fn msghdr_control_len(msg: &msghdr) -> usize { + msg.Control.len as _ +} + fn init() { static INIT: Once = Once::new(); @@ -853,6 +858,46 @@ pub(crate) fn to_mreqn( } } +#[cfg(feature = "all")] +pub(crate) fn original_dst(socket: Socket) -> io::Result { + unsafe { + SockAddr::try_init(|storage, len| { + syscall!( + getsockopt( + socket, + SOL_IP as i32, + SO_ORIGINAL_DST as i32, + storage.cast(), + len, + ), + PartialEq::eq, + SOCKET_ERROR + ) + }) + } + .map(|(_, addr)| addr) +} + +#[cfg(feature = "all")] +pub(crate) fn original_dst_ipv6(socket: Socket) -> io::Result { + unsafe { + SockAddr::try_init(|storage, len| { + syscall!( + getsockopt( + socket, + SOL_IP as i32, + IP6T_SO_ORIGINAL_DST as i32, + storage.cast(), + len, + ), + PartialEq::eq, + SOCKET_ERROR + ) + }) + } + .map(|(_, addr)| addr) +} + #[allow(unsafe_op_in_unsafe_fn)] pub(crate) fn unix_sockaddr(path: &Path) -> io::Result { // SAFETY: a `sockaddr_storage` of all zeros is valid. @@ -900,7 +945,6 @@ pub(crate) fn unix_sockaddr(path: &Path) -> io::Result { impl crate::Socket { /// Sets `HANDLE_FLAG_INHERIT` using `SetHandleInformation`. #[cfg(feature = "all")] - #[cfg_attr(docsrs, doc(cfg(all(windows, feature = "all"))))] pub fn set_no_inherit(&self, no_inherit: bool) -> io::Result<()> { self._set_no_inherit(no_inherit) } @@ -939,7 +983,6 @@ impl crate::Socket { } } -#[cfg_attr(docsrs, doc(cfg(windows)))] impl AsSocket for crate::Socket { fn as_socket(&self) -> BorrowedSocket<'_> { // SAFETY: lifetime is bound by self. @@ -947,14 +990,12 @@ impl AsSocket for crate::Socket { } } -#[cfg_attr(docsrs, doc(cfg(windows)))] impl AsRawSocket for crate::Socket { fn as_raw_socket(&self) -> RawSocket { self.as_raw() as RawSocket } } -#[cfg_attr(docsrs, doc(cfg(windows)))] impl From for OwnedSocket { fn from(sock: crate::Socket) -> OwnedSocket { // SAFETY: sock.into_raw() always returns a valid fd. @@ -962,14 +1003,12 @@ impl From for OwnedSocket { } } -#[cfg_attr(docsrs, doc(cfg(windows)))] impl IntoRawSocket for crate::Socket { fn into_raw_socket(self) -> RawSocket { self.into_raw() as RawSocket } } -#[cfg_attr(docsrs, doc(cfg(windows)))] impl From for crate::Socket { fn from(fd: OwnedSocket) -> crate::Socket { // SAFETY: `OwnedFd` ensures the fd is valid. @@ -977,7 +1016,6 @@ impl From for crate::Socket { } } -#[cfg_attr(docsrs, doc(cfg(windows)))] impl FromRawSocket for crate::Socket { unsafe fn from_raw_socket(socket: RawSocket) -> crate::Socket { crate::Socket::from_raw(socket as Socket) diff --git a/tests/socket.rs b/tests/socket.rs index a31255dd..a2dca668 100644 --- a/tests/socket.rs +++ b/tests/socket.rs @@ -5,6 +5,7 @@ target_os = "android", target_os = "freebsd", target_os = "ios", + target_os = "visionos", target_os = "linux", target_os = "macos", target_os = "tvos", @@ -29,6 +30,7 @@ use std::net::{Ipv6Addr, SocketAddrV6}; target_os = "android", target_os = "freebsd", target_os = "ios", + target_os = "visionos", target_os = "linux", target_os = "macos", target_os = "tvos", @@ -225,6 +227,7 @@ fn assert_common_flags(socket: &Socket, expected: bool) { assert_close_on_exec(socket, expected); #[cfg(any( target_os = "ios", + target_os = "visionos", target_os = "macos", target_os = "tvos", target_os = "watchos", @@ -416,6 +419,7 @@ where feature = "all", any( target_os = "ios", + target_os = "visionos", target_os = "macos", target_os = "tvos", target_os = "watchos", @@ -436,6 +440,7 @@ fn set_nosigpipe() { /// Assert that `SO_NOSIGPIPE` is set on `socket`. #[cfg(any( target_os = "ios", + target_os = "visionos", target_os = "macos", target_os = "tvos", target_os = "watchos", @@ -731,6 +736,10 @@ fn send_from_recv_to_vectored() { #[cfg(all(unix, not(target_os = "redox")))] assert_eq!(flags.is_out_of_band(), false); assert_eq!(flags.is_truncated(), false); + #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))] + assert_eq!(flags.is_confirm(), false); + #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))] + assert_eq!(flags.is_dontroute(), false); assert_eq!( addr.as_socket_ipv6().unwrap(), addr_a.as_socket_ipv6().unwrap() @@ -860,6 +869,7 @@ fn tcp_keepalive() { target_os = "freebsd", target_os = "fuchsia", target_os = "ios", + target_os = "visionos", target_os = "linux", target_os = "macos", target_os = "netbsd", @@ -877,6 +887,7 @@ fn tcp_keepalive() { target_os = "freebsd", target_os = "fuchsia", target_os = "ios", + target_os = "visionos", target_os = "linux", target_os = "macos", target_os = "netbsd", @@ -904,6 +915,7 @@ fn tcp_keepalive() { target_os = "fuchsia", target_os = "illumos", target_os = "ios", + target_os = "visionos", target_os = "linux", target_os = "macos", target_os = "netbsd", @@ -925,6 +937,7 @@ fn tcp_keepalive() { target_os = "fuchsia", target_os = "illumos", target_os = "ios", + target_os = "visionos", target_os = "linux", target_os = "macos", target_os = "netbsd", @@ -973,9 +986,12 @@ fn device() { feature = "all", any( target_os = "ios", + target_os = "visionos", target_os = "macos", target_os = "tvos", target_os = "watchos", + target_os = "solaris", + target_os = "illumos", ) ))] #[test] @@ -1018,9 +1034,12 @@ fn device() { feature = "all", any( target_os = "ios", + target_os = "visionos", target_os = "macos", target_os = "tvos", target_os = "watchos", + target_os = "solaris", + target_os = "illumos", ) ))] #[test] @@ -1065,6 +1084,7 @@ fn device_v6() { target_os = "android", target_os = "freebsd", target_os = "ios", + target_os = "visionos", target_os = "linux", target_os = "macos", target_os = "tvos", @@ -1222,6 +1242,7 @@ fn r#type() { unix, not(any( target_os = "ios", + target_os = "visionos", target_os = "macos", target_os = "tvos", target_os = "watchos", @@ -1349,8 +1370,8 @@ test!( #[cfg(all(feature = "all", target_os = "linux"))] test!( #[ignore = "setting `IP_TRANSPARENT` requires the `CAP_NET_ADMIN` capability (works when running as root)"] - ip_transparent, - set_ip_transparent(true) + ip_transparent_v4, + set_ip_transparent_v4(true) ); #[cfg(all(feature = "all", any(target_os = "fuchsia", target_os = "linux")))] test!( @@ -1384,7 +1405,7 @@ test!(freebind, set_freebind(true)); #[cfg(all(feature = "all", target_os = "linux"))] test!(IPv6 freebind_ipv6, set_freebind_ipv6(true)); -test!(IPv4 ttl, set_ttl(40)); +test!(IPv4 ttl_v4, set_ttl_v4(40)); #[cfg(not(any( target_os = "fuchsia", @@ -1393,7 +1414,7 @@ test!(IPv4 ttl, set_ttl(40)); target_os = "illumos", target_os = "haiku", )))] -test!(IPv4 tos, set_tos(96)); +test!(IPv4 tos_v4, set_tos_v4(96)); #[cfg(not(any( target_os = "dragonfly", @@ -1408,7 +1429,7 @@ test!(IPv4 tos, set_tos(96)); target_os = "vita", target_os = "haiku", )))] -test!(IPv4 recv_tos, set_recv_tos(true)); +test!(IPv4 recv_tos_v4, set_recv_tos_v4(true)); #[cfg(not(windows))] // TODO: returns `WSAENOPROTOOPT` (10042) on Windows. test!(IPv4 broadcast, set_broadcast(true)); @@ -1458,6 +1479,24 @@ test!(IPv6 tclass_v6, set_tclass_v6(96)); )))] test!(IPv6 recv_tclass_v6, set_recv_tclass_v6(true)); +#[cfg(all( + feature = "all", + not(any( + target_os = "dragonfly", + target_os = "fuchsia", + target_os = "hurd", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox", + target_os = "solaris", + target_os = "windows", + target_os = "vita", + target_os = "haiku", + )) +))] +test!(IPv6 recv_hoplimit_v6, set_recv_hoplimit_v6(true)); + #[cfg(all( feature = "all", any(target_os = "android", target_os = "fuchsia", target_os = "linux") @@ -1535,50 +1574,105 @@ fn header_included() { }; let initial = socket - .header_included() + .header_included_v4() .expect("failed to get initial value"); assert_eq!(initial, false, "initial value and argument are the same"); socket - .set_header_included(true) + .set_header_included_v4(true) .expect("failed to set option"); - let got = socket.header_included().expect("failed to get value"); + let got = socket.header_included_v4().expect("failed to get value"); assert_eq!(got, true, "set and get values differ"); } #[test] #[cfg(all( feature = "all", - any(target_os = "android", target_os = "fuchsia", target_os = "linux") + not(any( + target_os = "redox", + target_os = "espidf", + target_os = "openbsd", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "netbsd" + )) +))] +fn header_included_ipv6() { + let socket = match Socket::new(Domain::IPV6, Type::RAW, None) { + Ok(socket) => socket, + // Need certain permissions to create a raw sockets. + Err(ref err) if err.kind() == io::ErrorKind::PermissionDenied => return, + #[cfg(unix)] + Err(ref err) if err.raw_os_error() == Some(libc::EPROTONOSUPPORT) => return, + Err(err) => panic!("unexpected error creating socket: {}", err), + }; + + let initial = socket + .header_included_v6() + .expect("failed to get initial value"); + assert_eq!(initial, false, "initial value and argument are the same"); + + socket + .set_header_included_v6(true) + .expect("failed to set option"); + let got = socket.header_included_v6().expect("failed to get value"); + assert_eq!(got, true, "set and get values differ"); +} + +#[test] +#[cfg(all( + feature = "all", + any( + target_os = "android", + target_os = "fuchsia", + target_os = "linux", + target_os = "windows" + ) ))] fn original_dst() { let socket = Socket::new(Domain::IPV4, Type::STREAM, None).unwrap(); + #[cfg(not(target_os = "windows"))] + let expected = Some(libc::ENOENT); + #[cfg(target_os = "windows")] + let expected = Some(windows_sys::Win32::Networking::WinSock::WSAEINVAL); + match socket.original_dst() { Ok(_) => panic!("original_dst on non-redirected socket should fail"), - Err(err) => assert_eq!(err.raw_os_error(), Some(libc::ENOENT)), + Err(err) => assert_eq!(err.raw_os_error(), expected), } let socket = Socket::new(Domain::IPV6, Type::STREAM, None).unwrap(); match socket.original_dst() { Ok(_) => panic!("original_dst on non-redirected socket should fail"), - Err(err) => assert_eq!(err.raw_os_error(), Some(libc::ENOENT)), + Err(err) => assert_eq!(err.raw_os_error(), expected), } } #[test] -#[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))] +#[cfg(all( + feature = "all", + any(target_os = "android", target_os = "fuchsia", target_os = "linux") +))] fn original_dst_ipv6() { let socket = Socket::new(Domain::IPV6, Type::STREAM, None).unwrap(); + #[cfg(not(target_os = "windows"))] + let expected = Some(libc::ENOENT); + #[cfg(target_os = "windows")] + let expected = Some(windows_sys::Win32::Networking::WinSock::WSAEINVAL); + #[cfg(not(target_os = "windows"))] + let expected_v4 = Some(libc::EOPNOTSUPP); + #[cfg(target_os = "windows")] + let expected_v4 = Some(windows_sys::Win32::Networking::WinSock::WSAEINVAL); match socket.original_dst_ipv6() { Ok(_) => panic!("original_dst_ipv6 on non-redirected socket should fail"), - Err(err) => assert_eq!(err.raw_os_error(), Some(libc::ENOENT)), + Err(err) => assert_eq!(err.raw_os_error(), expected), } // Not supported on IPv4 socket. let socket = Socket::new(Domain::IPV4, Type::STREAM, None).unwrap(); match socket.original_dst_ipv6() { Ok(_) => panic!("original_dst_ipv6 on non-redirected socket should fail"), - Err(err) => assert_eq!(err.raw_os_error(), Some(libc::EOPNOTSUPP)), + Err(err) => assert_eq!(err.raw_os_error(), expected_v4), } } @@ -1676,3 +1770,19 @@ fn cookie() { Err(err) => panic!("Could not get socket cookie a second time, err: {err}"), } } + +#[cfg(all(unix, target_os = "linux"))] +#[test] +fn set_passcred() { + let socket = Socket::new(Domain::UNIX, Type::DGRAM, None).unwrap(); + assert!(!socket.passcred().unwrap()); + + socket.set_passcred(true).unwrap(); + assert!(socket.passcred().unwrap()); + + let socket = Socket::new(Domain::UNIX, Type::STREAM, None).unwrap(); + assert!(!socket.passcred().unwrap()); + + socket.set_passcred(true).unwrap(); + assert!(socket.passcred().unwrap()); +}