diff --git a/src/socket.rs b/src/socket.rs index 5900e0c2..70213b55 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -1445,8 +1445,6 @@ impl Socket { target_os = "solaris", )))] pub fn set_recv_tos(&self, recv_tos: bool) -> io::Result<()> { - let recv_tos = i32::from(recv_tos); - unsafe { setsockopt( self.as_raw(), @@ -1668,6 +1666,52 @@ impl Socket { ) } } + + /// Get the value of the `IPV6_RECVTCLASS` option for this socket. + /// + /// For more information about this option, see [`set_recv_tclass_v6`]. + /// + /// [`set_recv_tclass_v6`]: Socket::set_recv_tclass_v6 + #[cfg(not(any( + target_os = "dragonfly", + target_os = "fuchsia", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox", + target_os = "solaris", + )))] + pub fn recv_tclass_v6(&self) -> io::Result { + unsafe { + getsockopt::(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_RECVTCLASS) + .map(|recv_tclass| recv_tclass > 0) + } + } + + /// Set the value of the `IPV6_RECVTCLASS` option for this socket. + /// + /// If enabled, the `IPV6_TCLASS` ancillary message is passed with incoming + /// packets. It contains a byte which specifies the traffic class field of + /// the packet header. + #[cfg(not(any( + target_os = "dragonfly", + target_os = "fuchsia", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox", + target_os = "solaris", + )))] + pub fn set_recv_tclass_v6(&self, recv_tclass: bool) -> io::Result<()> { + unsafe { + setsockopt( + self.as_raw(), + sys::IPPROTO_IPV6, + sys::IPV6_RECVTCLASS, + recv_tclass as c_int, + ) + } + } } /// Socket options for TCP sockets, get/set using `IPPROTO_TCP`. diff --git a/src/sys/unix.rs b/src/sys/unix.rs index 972dfe14..cae633ae 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -76,6 +76,16 @@ pub(crate) use libc::{ #[cfg(not(target_os = "redox"))] pub(crate) use libc::{MSG_TRUNC, SO_OOBINLINE}; // Used in `Socket`. +#[cfg(not(any( + target_os = "dragonfly", + target_os = "fuchsia", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox", + target_os = "solaris", +)))] +pub(crate) use libc::IPV6_RECVTCLASS; #[cfg(all(feature = "all", not(target_os = "redox")))] pub(crate) use libc::IP_HDRINCL; #[cfg(not(any( @@ -2057,6 +2067,91 @@ impl crate::Socket { pub fn detach_filter(&self) -> io::Result<()> { unsafe { setsockopt(self.as_raw(), libc::SOL_SOCKET, libc::SO_DETACH_FILTER, 0) } } + + /// Get the value of the `IPV6_TCLASS` option for this socket. + /// + /// For more information about this option, see [`set_tclass_v6`]. + /// + /// [`set_tclass_v6`]: Socket::set_tclass_v6 + #[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" + ) + ))] + #[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) + .map(|tclass| tclass as u32) + } + } + + /// Set the value of the `IPV6_TCLASS` option for this socket. + /// + /// Specifies the traffic class field that is used in every packets + /// sent from this socket. + #[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" + ) + ))] + #[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( + self.as_raw(), + IPPROTO_IPV6, + libc::IPV6_TCLASS, + tclass as c_int, + ) + } + } } #[cfg_attr(docsrs, doc(cfg(unix)))] diff --git a/src/sys/windows.rs b/src/sys/windows.rs index 03e1a60a..c9e57dd1 100644 --- a/src/sys/windows.rs +++ b/src/sys/windows.rs @@ -69,12 +69,13 @@ pub(crate) type socklen_t = i32; pub(crate) use windows_sys::Win32::Networking::WinSock::IP_HDRINCL; pub(crate) use windows_sys::Win32::Networking::WinSock::{ linger, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP, IPV6_MREQ as Ipv6Mreq, - IPV6_MULTICAST_HOPS, IPV6_MULTICAST_IF, IPV6_MULTICAST_LOOP, IPV6_UNICAST_HOPS, IPV6_V6ONLY, - IP_ADD_MEMBERSHIP, IP_ADD_SOURCE_MEMBERSHIP, IP_DROP_MEMBERSHIP, IP_DROP_SOURCE_MEMBERSHIP, - IP_MREQ as IpMreq, IP_MREQ_SOURCE as IpMreqSource, IP_MULTICAST_IF, IP_MULTICAST_LOOP, - IP_MULTICAST_TTL, IP_RECVTOS, IP_TOS, IP_TTL, MSG_OOB, MSG_PEEK, SO_BROADCAST, SO_ERROR, - SO_KEEPALIVE, SO_LINGER, SO_OOBINLINE, SO_RCVBUF, SO_RCVTIMEO, SO_REUSEADDR, SO_SNDBUF, - SO_SNDTIMEO, SO_TYPE, TCP_NODELAY, + IPV6_MULTICAST_HOPS, IPV6_MULTICAST_IF, IPV6_MULTICAST_LOOP, IPV6_RECVTCLASS, + IPV6_UNICAST_HOPS, IPV6_V6ONLY, IP_ADD_MEMBERSHIP, IP_ADD_SOURCE_MEMBERSHIP, + IP_DROP_MEMBERSHIP, IP_DROP_SOURCE_MEMBERSHIP, IP_MREQ as IpMreq, + IP_MREQ_SOURCE as IpMreqSource, IP_MULTICAST_IF, IP_MULTICAST_LOOP, IP_MULTICAST_TTL, + IP_RECVTOS, IP_TOS, IP_TTL, MSG_OOB, MSG_PEEK, SO_BROADCAST, SO_ERROR, SO_KEEPALIVE, SO_LINGER, + SO_OOBINLINE, SO_RCVBUF, SO_RCVTIMEO, SO_REUSEADDR, SO_SNDBUF, SO_SNDTIMEO, SO_TYPE, + TCP_NODELAY, }; pub(crate) const IPPROTO_IP: c_int = windows_sys::Win32::Networking::WinSock::IPPROTO_IP as c_int; pub(crate) const SOL_SOCKET: c_int = windows_sys::Win32::Networking::WinSock::SOL_SOCKET as c_int; diff --git a/tests/socket.rs b/tests/socket.rs index 54c8cd9c..5ca6eb5d 100644 --- a/tests/socket.rs +++ b/tests/socket.rs @@ -1218,6 +1218,33 @@ test!(IPv6 only_v6, set_only_v6(true)); #[cfg(any(windows, target_os = "freebsd"))] test!(IPv6 only_v6, set_only_v6(false)); +#[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" + ) +))] +test!(IPv6 tclass_v6, set_tclass_v6(96)); + +#[cfg(not(any( + target_os = "dragonfly", + target_os = "fuchsia", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox", + target_os = "solaris", + target_os = "windows", +)))] +test!(IPv6 recv_tclass_v6, set_recv_tclass_v6(true)); + #[cfg(all( feature = "all", any(target_os = "android", target_os = "fuchsia", target_os = "linux")