diff options
Diffstat (limited to 'vendor/socket2')
-rw-r--r-- | vendor/socket2/.cargo-checksum.json | 2 | ||||
-rw-r--r-- | vendor/socket2/Cargo.toml | 49 | ||||
-rw-r--r-- | vendor/socket2/README.md | 4 | ||||
-rw-r--r-- | vendor/socket2/src/lib.rs | 68 | ||||
-rw-r--r-- | vendor/socket2/src/sockaddr.rs | 4 | ||||
-rw-r--r-- | vendor/socket2/src/socket.rs | 309 | ||||
-rw-r--r-- | vendor/socket2/src/sys/unix.rs | 400 | ||||
-rw-r--r-- | vendor/socket2/src/sys/windows.rs | 74 |
8 files changed, 841 insertions, 69 deletions
diff --git a/vendor/socket2/.cargo-checksum.json b/vendor/socket2/.cargo-checksum.json index b46b01bcd..0ec9465ba 100644 --- a/vendor/socket2/.cargo-checksum.json +++ b/vendor/socket2/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"132904af796323d037c82381fc97a3f1d696f93c128fc7b2009d827dfdd5230f","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"b870d442505bc8047b641815c8283f29fc213dcfd1331894802e6ae55cc09f1b","src/lib.rs":"df42802e8487a5491957d13c6fe987a81f0ac4b766809b104279df65908040ea","src/sockaddr.rs":"da658f12e226ea69e2f4880c24c023db1ea11e6609c596fa2abdaf0296fce427","src/socket.rs":"f99ab91141609de7016fa972aad0ba9e4e57bbf0c690cd436b7a0f765bae1a74","src/sockref.rs":"02de263cce039aaddaee5d6c2bb3940bdfae5697a3fc9df47d226fb3cac03cd9","src/sys/unix.rs":"59c6d13c6dd0edbd388df4ac3404765469144ed356ef7a03127a75f11cff6058","src/sys/windows.rs":"9bcd8446e5f0aac866dc1c673568652a40fd54cbf699e33262bd2a1055974437"},"package":"765f090f0e423d2b55843402a07915add955e7d60657db13707a159727326cad"}
\ No newline at end of file +{"files":{"Cargo.toml":"a923f376ccc72eace3803c02342d6ef8c1d0fde8af4fcdb3e86bc55e4b31e800","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"b3fadb399050f2755504188e81dec8150f6a1eba86b6410a9ce9c1ea0c850287","src/lib.rs":"0805b736e0cde0ae1d064ff1887f8ae37b219d17309d427be122d5ccd51c116b","src/sockaddr.rs":"a2b7f7c8959b8ff1546d1f1b38f305b22607d7a59c0698e5a8f9cfd81e4b8ede","src/socket.rs":"bd938d210a9763b0ed3395b192698c36c4f88e44adb8f3aaf12a6743efeffa2a","src/sockref.rs":"02de263cce039aaddaee5d6c2bb3940bdfae5697a3fc9df47d226fb3cac03cd9","src/sys/unix.rs":"6db80abf67e6a4555280eba076371798cab333fcb4729fab2a460a5d709f9667","src/sys/windows.rs":"d271c768295c0f84e79f6286aa783ce15ab0265f150195824fdcd10003dada33"},"package":"64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662"}
\ No newline at end of file diff --git a/vendor/socket2/Cargo.toml b/vendor/socket2/Cargo.toml index 521c43c2c..3f1578ccb 100644 --- a/vendor/socket2/Cargo.toml +++ b/vendor/socket2/Cargo.toml @@ -12,28 +12,57 @@ [package] edition = "2018" name = "socket2" -version = "0.4.1" -authors = ["Alex Crichton <alex@alexcrichton.com>", "Thomas de Zeeuw <thomasdezeeuw@gmail.com>"] -include = ["Cargo.toml", "LICENSE-APACHE", "LICENSE-MIT", "README.md", "src/**/*.rs"] -description = "Utilities for handling networking sockets with a maximal amount of configuration\npossible intended.\n" +version = "0.4.9" +authors = [ + "Alex Crichton <alex@alexcrichton.com>", + "Thomas de Zeeuw <thomasdezeeuw@gmail.com>", +] +include = [ + "Cargo.toml", + "LICENSE-APACHE", + "LICENSE-MIT", + "README.md", + "src/**/*.rs", +] +description = """ +Utilities for handling networking sockets with a maximal amount of configuration +possible intended. +""" homepage = "https://github.com/rust-lang/socket2" documentation = "https://docs.rs/socket2" readme = "README.md" -keywords = ["io", "socket", "network"] -categories = ["api-bindings", "network-programming"] -license = "MIT/Apache-2.0" +keywords = [ + "io", + "socket", + "network", +] +categories = [ + "api-bindings", + "network-programming", +] +license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/socket2" + [package.metadata.docs.rs] all-features = true -rustdoc-args = ["--cfg", "docsrs"] +rustdoc-args = [ + "--cfg", + "docsrs", +] [package.metadata.playground] features = ["all"] [features] all = [] + [target."cfg(unix)".dependencies.libc] -version = "0.2.96" +version = "0.2.139" + [target."cfg(windows)".dependencies.winapi] version = "0.3.9" -features = ["handleapi", "ws2ipdef", "ws2tcpip"] +features = [ + "handleapi", + "ws2ipdef", + "ws2tcpip", +] diff --git a/vendor/socket2/README.md b/vendor/socket2/README.md index 45f4cf84b..77963b746 100644 --- a/vendor/socket2/README.md +++ b/vendor/socket2/README.md @@ -71,9 +71,9 @@ Socket2 uses 1.46.0 as MSRV. This project is licensed under either of * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or - http://www.apache.org/licenses/LICENSE-2.0) + https://www.apache.org/licenses/LICENSE-2.0) * MIT license ([LICENSE-MIT](LICENSE-MIT) or - http://opensource.org/licenses/MIT) + https://opensource.org/licenses/MIT) at your option. diff --git a/vendor/socket2/src/lib.rs b/vendor/socket2/src/lib.rs index 6ea3cc229..a2e2ffcb8 100644 --- a/vendor/socket2/src/lib.rs +++ b/vendor/socket2/src/lib.rs @@ -1,8 +1,8 @@ // Copyright 2015 The Rust Project Developers. // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. @@ -34,9 +34,9 @@ //! // Create a TCP listener bound to two addresses. //! let socket = Socket::new(Domain::IPV6, Type::STREAM, None)?; //! +//! socket.set_only_v6(false)?; //! let address: SocketAddr = "[::1]:12345".parse().unwrap(); //! socket.bind(&address.into())?; -//! socket.set_only_v6(false)?; //! socket.listen(128)?; //! //! let listener: TcpListener = socket.into(); @@ -50,7 +50,7 @@ //! This crate has a single feature `all`, which enables all functions even ones //! that are not available on all OSs. -#![doc(html_root_url = "https://docs.rs/socket2/0.3")] +#![doc(html_root_url = "https://docs.rs/socket2/0.4")] #![deny(missing_docs, missing_debug_implementations, rust_2018_idioms)] // Show required OS/features on docs.rs. #![cfg_attr(docsrs, feature(doc_cfg))] @@ -119,19 +119,28 @@ mod sockaddr; mod socket; mod sockref; -#[cfg(unix)] -#[path = "sys/unix.rs"] -mod sys; -#[cfg(windows)] -#[path = "sys/windows.rs"] +#[cfg_attr(unix, path = "sys/unix.rs")] +#[cfg_attr(windows, path = "sys/windows.rs")] mod sys; +#[cfg(not(any(windows, unix)))] +compile_error!("Socket2 doesn't support the compile target"); + use sys::c_int; pub use sockaddr::SockAddr; pub use socket::Socket; pub use sockref::SockRef; +#[cfg(not(any( + target_os = "haiku", + target_os = "illumos", + target_os = "netbsd", + target_os = "redox", + target_os = "solaris", +)))] +pub use socket::InterfaceIndexOrAddress; + /// Specification of the communication domain for a socket. /// /// This is a newtype wrapper around an integer which provides a nicer API in @@ -282,10 +291,6 @@ impl RecvFlags { #[repr(transparent)] pub struct MaybeUninitSlice<'a>(sys::MaybeUninitSlice<'a>); -unsafe impl<'a> Send for MaybeUninitSlice<'a> {} - -unsafe impl<'a> Sync for MaybeUninitSlice<'a> {} - impl<'a> fmt::Debug for MaybeUninitSlice<'a> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(self.0.as_slice(), fmt) @@ -322,8 +327,22 @@ impl<'a> DerefMut for MaybeUninitSlice<'a> { /// See [`Socket::set_tcp_keepalive`]. #[derive(Debug, Clone)] pub struct TcpKeepalive { + #[cfg_attr(target_os = "openbsd", allow(dead_code))] time: Option<Duration>, + #[cfg(not(any( + target_os = "openbsd", + target_os = "redox", + target_os = "solaris", + target_os = "nto", + )))] interval: Option<Duration>, + #[cfg(not(any( + target_os = "openbsd", + target_os = "redox", + target_os = "solaris", + target_os = "windows", + target_os = "nto", + )))] retries: Option<u32>, } @@ -332,7 +351,20 @@ impl TcpKeepalive { pub const fn new() -> TcpKeepalive { TcpKeepalive { time: None, + #[cfg(not(any( + target_os = "openbsd", + target_os = "redox", + target_os = "solaris", + target_os = "nto", + )))] interval: None, + #[cfg(not(any( + target_os = "openbsd", + target_os = "redox", + target_os = "solaris", + target_os = "windows", + target_os = "nto", + )))] retries: None, } } @@ -365,9 +397,11 @@ impl TcpKeepalive { #[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_vendor = "apple", @@ -379,8 +413,11 @@ impl TcpKeepalive { 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_vendor = "apple", @@ -403,9 +440,11 @@ impl TcpKeepalive { feature = "all", any( doc, + target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "fuchsia", + target_os = "illumos", target_os = "linux", target_os = "netbsd", target_vendor = "apple", @@ -416,8 +455,11 @@ impl TcpKeepalive { 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_vendor = "apple", diff --git a/vendor/socket2/src/sockaddr.rs b/vendor/socket2/src/sockaddr.rs index 8a789571f..9ce638e9a 100644 --- a/vendor/socket2/src/sockaddr.rs +++ b/vendor/socket2/src/sockaddr.rs @@ -13,6 +13,7 @@ use winapi::shared::ws2ipdef::SOCKADDR_IN6_LH_u; /// /// `SockAddr`s may be constructed directly to and from the standard library /// [`SocketAddr`], [`SocketAddrV4`], and [`SocketAddrV6`] types. +#[derive(Clone)] pub struct SockAddr { storage: sockaddr_storage, len: socklen_t, @@ -224,7 +225,7 @@ impl From<SocketAddrV4> for SockAddr { let sockaddr_in = sockaddr_in { sin_family: AF_INET as sa_family_t, sin_port: addr.port().to_be(), - sin_addr: crate::sys::to_in_addr(&addr.ip()), + sin_addr: crate::sys::to_in_addr(addr.ip()), sin_zero: Default::default(), #[cfg(any( target_os = "dragonfly", @@ -301,6 +302,7 @@ impl fmt::Debug for SockAddr { target_os = "netbsd", target_os = "openbsd", target_os = "vxworks", + target_os = "nto", ))] f.field("ss_len", &self.storage.ss_len); f.field("ss_family", &self.storage.ss_family) diff --git a/vendor/socket2/src/socket.rs b/vendor/socket2/src/socket.rs index bc9b77da0..69d0478dd 100644 --- a/vendor/socket2/src/socket.rs +++ b/vendor/socket2/src/socket.rs @@ -1,8 +1,8 @@ // Copyright 2015 The Rust Project Developers. // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. @@ -11,7 +11,9 @@ use std::io::{self, Read, Write}; #[cfg(not(target_os = "redox"))] use std::io::{IoSlice, IoSliceMut}; use std::mem::MaybeUninit; -use std::net::{self, Ipv4Addr, Ipv6Addr, Shutdown}; +#[cfg(not(target_os = "nto"))] +use std::net::Ipv6Addr; +use std::net::{self, Ipv4Addr, Shutdown}; #[cfg(unix)] use std::os::unix::io::{FromRawFd, IntoRawFd}; #[cfg(windows)] @@ -32,9 +34,11 @@ use crate::{MaybeUninitSlice, RecvFlags}; /// precisely one libc or OS API call which is essentially just a "Rustic /// translation" of what's below. /// +/// ## Converting to and from other types +/// /// This type can be freely converted into the network primitives provided by /// the standard library, such as [`TcpStream`] or [`UdpSocket`], using the -/// [`Into`] trait, see the example below. +/// [`From`] trait, see the example below. /// /// [`TcpStream`]: std::net::TcpStream /// [`UdpSocket`]: std::net::UdpSocket @@ -560,11 +564,36 @@ impl Socket { /// `peek_from` makes the same safety guarantees regarding the `buf`fer as /// [`recv`]. /// + /// # Note: Datagram Sockets + /// For datagram sockets, the behavior of this method when `buf` is smaller than + /// the datagram at the head of the receive queue differs between Windows and + /// Unix-like platforms (Linux, macOS, BSDs, etc: colloquially termed "*nix"). + /// + /// On *nix platforms, the datagram is truncated to the length of `buf`. + /// + /// On Windows, an error corresponding to `WSAEMSGSIZE` will be returned. + /// + /// For consistency between platforms, be sure to provide a sufficiently large buffer to avoid + /// truncation; the exact size required depends on the underlying protocol. + /// + /// If you just want to know the sender of the data, try [`peek_sender`]. + /// /// [`recv`]: Socket::recv + /// [`peek_sender`]: Socket::peek_sender pub fn peek_from(&self, buf: &mut [MaybeUninit<u8>]) -> io::Result<(usize, SockAddr)> { self.recv_from_with_flags(buf, sys::MSG_PEEK) } + /// Retrieve the sender for the data at the head of the receive queue. + /// + /// This is equivalent to calling [`peek_from`] with a zero-sized buffer, + /// but suppresses the `WSAEMSGSIZE` error on Windows. + /// + /// [`peek_from`]: Socket::peek_from + pub fn peek_sender(&self) -> io::Result<SockAddr> { + sys::peek_sender(self.as_raw()) + } + /// Sends data on the socket to a connected peer. /// /// This is typically used on TCP sockets or datagram sockets which have @@ -711,6 +740,25 @@ fn set_common_flags(socket: Socket) -> io::Result<Socket> { Ok(socket) } +/// A local interface specified by its index or an address assigned to it. +/// +/// `Index(0)` and `Address(Ipv4Addr::UNSPECIFIED)` are equivalent and indicate +/// that an appropriate interface should be selected by the system. +#[cfg(not(any( + target_os = "haiku", + target_os = "illumos", + target_os = "netbsd", + target_os = "redox", + target_os = "solaris", +)))] +#[derive(Debug)] +pub enum InterfaceIndexOrAddress { + /// An interface index. + Index(u32), + /// An address assigned to an interface. + Address(Ipv4Addr), +} + /// Socket options get/set using `SOL_SOCKET`. /// /// Additional documentation can be found in documentation of the OS. @@ -989,6 +1037,44 @@ fn into_linger(duration: Option<Duration>) -> sys::linger { /// * Linux: <https://man7.org/linux/man-pages/man7/ip.7.html> /// * Windows: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options> impl Socket { + /// Get the value of the `IP_HDRINCL` option on this socket. + /// + /// For more information about this option, see [`set_header_included`]. + /// + /// [`set_header_included`]: Socket::set_header_included + #[cfg(all(feature = "all", not(target_os = "redox")))] + #[cfg_attr(docsrs, doc(all(feature = "all", not(target_os = "redox"))))] + pub fn header_included(&self) -> io::Result<bool> { + unsafe { + getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, 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`, [`IP_TTL`], + /// and [`IP_TOS`] are ignored. + /// + /// [`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 + #[cfg(all(feature = "all", not(target_os = "redox")))] + #[cfg_attr(docsrs, doc(all(feature = "all", not(target_os = "redox"))))] + pub fn set_header_included(&self, included: bool) -> io::Result<()> { + unsafe { + setsockopt( + self.as_raw(), + sys::IPPROTO_IP, + sys::IP_HDRINCL, + included as c_int, + ) + } + } + /// Get the value of the `IP_TRANSPARENT` option on this socket. /// /// For more information about this option, see [`set_ip_transparent`]. @@ -1014,7 +1100,7 @@ impl Socket { /// are routed through the TProxy box (i.e., the system /// hosting the application that employs the IP_TRANSPARENT /// socket option). Enabling this socket option requires - /// superuser privileges (the CAP_NET_ADMIN capability). + /// superuser privileges (the `CAP_NET_ADMIN` capability). /// /// TProxy redirection with the iptables TPROXY target also /// requires that this option be set on the redirected socket. @@ -1066,6 +1152,139 @@ impl Socket { } } + /// Join a multicast group using `IP_ADD_MEMBERSHIP` option on this socket. + /// + /// This function specifies a new multicast group for this socket to join. + /// The address must be a valid multicast address, and `interface` specifies + /// the local interface with which the system should join the multicast + /// group. See [`InterfaceIndexOrAddress`]. + #[cfg(not(any( + target_os = "haiku", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox", + target_os = "solaris", + target_os = "nto", + )))] + pub fn join_multicast_v4_n( + &self, + multiaddr: &Ipv4Addr, + interface: &InterfaceIndexOrAddress, + ) -> io::Result<()> { + let mreqn = sys::to_mreqn(multiaddr, interface); + unsafe { + setsockopt( + self.as_raw(), + sys::IPPROTO_IP, + sys::IP_ADD_MEMBERSHIP, + mreqn, + ) + } + } + + /// Leave a multicast group using `IP_DROP_MEMBERSHIP` option on this socket. + /// + /// For more information about this option, see [`join_multicast_v4_n`]. + /// + /// [`join_multicast_v4_n`]: Socket::join_multicast_v4_n + #[cfg(not(any( + target_os = "haiku", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox", + target_os = "solaris", + target_os = "nto", + )))] + pub fn leave_multicast_v4_n( + &self, + multiaddr: &Ipv4Addr, + interface: &InterfaceIndexOrAddress, + ) -> io::Result<()> { + let mreqn = sys::to_mreqn(multiaddr, interface); + unsafe { + setsockopt( + self.as_raw(), + sys::IPPROTO_IP, + sys::IP_DROP_MEMBERSHIP, + mreqn, + ) + } + } + + /// Join a multicast SSM channel using `IP_ADD_SOURCE_MEMBERSHIP` option on this socket. + /// + /// This function specifies a new multicast channel for this socket to join. + /// The group must be a valid SSM group address, the source must be the address of the sender + /// and `interface` is the address of the local interface with which the system should join the + /// multicast group. If it's [`Ipv4Addr::UNSPECIFIED`] (`INADDR_ANY`) then + /// an appropriate interface is chosen by the system. + #[cfg(not(any( + target_os = "dragonfly", + target_os = "haiku", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox", + target_os = "fuchsia", + target_os = "nto", + )))] + pub fn join_ssm_v4( + &self, + source: &Ipv4Addr, + group: &Ipv4Addr, + interface: &Ipv4Addr, + ) -> io::Result<()> { + let mreqs = sys::IpMreqSource { + imr_multiaddr: sys::to_in_addr(group), + imr_interface: sys::to_in_addr(interface), + imr_sourceaddr: sys::to_in_addr(source), + }; + unsafe { + setsockopt( + self.as_raw(), + sys::IPPROTO_IP, + sys::IP_ADD_SOURCE_MEMBERSHIP, + mreqs, + ) + } + } + + /// Leave a multicast group using `IP_DROP_SOURCE_MEMBERSHIP` option on this socket. + /// + /// For more information about this option, see [`join_ssm_v4`]. + /// + /// [`join_ssm_v4`]: Socket::join_ssm_v4 + #[cfg(not(any( + target_os = "dragonfly", + target_os = "haiku", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox", + target_os = "fuchsia", + target_os = "nto", + )))] + pub fn leave_ssm_v4( + &self, + source: &Ipv4Addr, + group: &Ipv4Addr, + interface: &Ipv4Addr, + ) -> io::Result<()> { + let mreqs = sys::IpMreqSource { + imr_multiaddr: sys::to_in_addr(group), + imr_interface: sys::to_in_addr(interface), + imr_sourceaddr: sys::to_in_addr(source), + }; + unsafe { + setsockopt( + self.as_raw(), + sys::IPPROTO_IP, + sys::IP_DROP_SOURCE_MEMBERSHIP, + mreqs, + ) + } + } + /// Get the value of the `IP_MULTICAST_IF` option for this socket. /// /// For more information about this option, see [`set_multicast_if_v4`]. @@ -1176,7 +1395,7 @@ impl Socket { /// NOTE: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options> /// documents that not all versions of windows support `IP_TOS`. #[cfg(not(any( - target_os = "fuschia", + target_os = "fuchsia", target_os = "redox", target_os = "solaris", target_os = "illumos", @@ -1191,9 +1410,10 @@ impl Socket { /// /// NOTE: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options> /// documents that not all versions of windows support `IP_TOS`. + /// /// [`set_tos`]: Socket::set_tos #[cfg(not(any( - target_os = "fuschia", + target_os = "fuchsia", target_os = "redox", target_os = "solaris", target_os = "illumos", @@ -1203,6 +1423,58 @@ impl Socket { getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_TOS).map(|tos| tos as u32) } } + + /// Set the value of the `IP_RECVTOS` option for this socket. + /// + /// If enabled, the IP_TOS ancillary message is passed with + /// incoming packets. It contains a byte which specifies the + /// Type of Service/Precedence 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", + target_os = "windows", + target_os = "nto", + )))] + pub fn set_recv_tos(&self, recv_tos: bool) -> io::Result<()> { + let recv_tos = if recv_tos { 1 } else { 0 }; + + unsafe { + setsockopt( + self.as_raw(), + sys::IPPROTO_IP, + sys::IP_RECVTOS, + recv_tos as c_int, + ) + } + } + + /// Get the value of the `IP_RECVTOS` option for this socket. + /// + /// For more information about this option, see [`set_recv_tos`]. + /// + /// [`set_recv_tos`]: Socket::set_recv_tos + #[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", + target_os = "nto", + )))] + pub fn recv_tos(&self) -> io::Result<bool> { + unsafe { + getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_RECVTOS) + .map(|recv_tos| recv_tos > 0) + } + } } /// Socket options for IPv6 sockets, get/set using `IPPROTO_IPV6`. @@ -1218,6 +1490,7 @@ impl Socket { /// This function specifies a new multicast group for this socket to join. /// The address must be a valid multicast address, and `interface` is the /// index of the interface to join/leave (or 0 to indicate any interface). + #[cfg(not(target_os = "nto"))] pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { let mreq = sys::Ipv6Mreq { ipv6mr_multiaddr: sys::to_in6_addr(multiaddr), @@ -1241,6 +1514,7 @@ impl Socket { /// For more information about this option, see [`join_multicast_v6`]. /// /// [`join_multicast_v6`]: Socket::join_multicast_v6 + #[cfg(not(target_os = "nto"))] pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { let mreq = sys::Ipv6Mreq { ipv6mr_multiaddr: sys::to_in6_addr(multiaddr), @@ -1404,11 +1678,22 @@ impl Socket { impl Socket { /// Get the value of the `TCP_KEEPIDLE` option on this socket. /// - /// This returns the value of `SO_KEEPALIVE` on OpenBSD and Haiku, - /// `TCP_KEEPALIVE` on macOS and iOS, and `TCP_KEEPIDLE` on all other Unix - /// operating systems. - #[cfg(any(doc, all(feature = "all", not(windows))))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "all", not(windows)))))] + /// This returns the value of `TCP_KEEPALIVE` on macOS and iOS and `TCP_KEEPIDLE` on all other + /// supported Unix operating systems. + #[cfg(any( + doc, + all( + feature = "all", + not(any(windows, target_os = "haiku", target_os = "openbsd")) + ) + ))] + #[cfg_attr( + docsrs, + doc(cfg(all( + feature = "all", + not(any(windows, target_os = "haiku", target_os = "openbsd")) + ))) + )] pub fn keepalive_time(&self) -> io::Result<Duration> { sys::keepalive_time(self.as_raw()) } diff --git a/vendor/socket2/src/sys/unix.rs b/vendor/socket2/src/sys/unix.rs index a497830fa..74da8cc20 100644 --- a/vendor/socket2/src/sys/unix.rs +++ b/vendor/socket2/src/sys/unix.rs @@ -1,8 +1,8 @@ // Copyright 2015 The Rust Project Developers. // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. @@ -75,8 +75,24 @@ pub(crate) use libc::{ #[cfg(not(target_os = "redox"))] pub(crate) use libc::{MSG_TRUNC, SO_OOBINLINE}; // Used in `Socket`. +#[cfg(not(target_os = "nto"))] +pub(crate) use libc::ipv6_mreq as Ipv6Mreq; +#[cfg(all(feature = "all", not(target_os = "redox")))] +pub(crate) use libc::IP_HDRINCL; #[cfg(not(any( - target_os = "fuschia", + 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 = "nto", +)))] +pub(crate) use libc::IP_RECVTOS; +#[cfg(not(any( + target_os = "fuchsia", target_os = "redox", target_os = "solaris", target_os = "illumos", @@ -87,11 +103,23 @@ pub(crate) use libc::SO_LINGER; #[cfg(target_vendor = "apple")] pub(crate) use libc::SO_LINGER_SEC as SO_LINGER; pub(crate) use libc::{ - ip_mreq as IpMreq, ipv6_mreq as Ipv6Mreq, 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, IP_MULTICAST_IF, IP_MULTICAST_LOOP, IP_MULTICAST_TTL, - IP_TTL, MSG_OOB, MSG_PEEK, SOL_SOCKET, SO_BROADCAST, SO_ERROR, SO_KEEPALIVE, SO_RCVBUF, - SO_RCVTIMEO, SO_REUSEADDR, SO_SNDBUF, SO_SNDTIMEO, SO_TYPE, TCP_NODELAY, + 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, + IP_MULTICAST_IF, IP_MULTICAST_LOOP, IP_MULTICAST_TTL, IP_TTL, MSG_OOB, MSG_PEEK, SOL_SOCKET, + SO_BROADCAST, SO_ERROR, SO_KEEPALIVE, SO_RCVBUF, SO_RCVTIMEO, SO_REUSEADDR, SO_SNDBUF, + SO_SNDTIMEO, SO_TYPE, TCP_NODELAY, +}; +#[cfg(not(any( + target_os = "dragonfly", + target_os = "haiku", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox", + target_os = "fuchsia", + target_os = "nto", +)))] +pub(crate) use libc::{ + ip_mreq_source as IpMreqSource, IP_ADD_SOURCE_MEMBERSHIP, IP_DROP_SOURCE_MEMBERSHIP, }; #[cfg(not(any( target_os = "dragonfly", @@ -101,6 +129,7 @@ pub(crate) use libc::{ target_os = "netbsd", target_os = "openbsd", target_os = "solaris", + target_os = "nto", target_vendor = "apple" )))] pub(crate) use libc::{IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP}; @@ -135,9 +164,14 @@ pub(crate) use libc::{TCP_KEEPCNT, TCP_KEEPINTVL}; // See this type in the Windows file. pub(crate) type Bool = c_int; -#[cfg(target_vendor = "apple")] +#[cfg(any(target_vendor = "apple", target_os = "nto"))] use libc::TCP_KEEPALIVE as KEEPALIVE_TIME; -#[cfg(not(any(target_vendor = "apple", target_os = "haiku", target_os = "openbsd")))] +#[cfg(not(any( + target_vendor = "apple", + target_os = "haiku", + target_os = "openbsd", + target_os = "nto", +)))] use libc::TCP_KEEPIDLE as KEEPALIVE_TIME; /// Helper macro to execute a system call that returns an `io::Result`. @@ -196,6 +230,7 @@ type IovLen = usize; target_os = "netbsd", target_os = "openbsd", target_os = "solaris", + target_os = "nto", target_vendor = "apple", ))] type IovLen = c_int; @@ -414,6 +449,10 @@ pub struct MaybeUninitSlice<'a> { _lifetime: PhantomData<&'a mut [MaybeUninit<u8>]>, } +unsafe impl<'a> Send for MaybeUninitSlice<'a> {} + +unsafe impl<'a> Sync for MaybeUninitSlice<'a> {} + impl<'a> MaybeUninitSlice<'a> { pub(crate) fn new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a> { MaybeUninitSlice { @@ -713,6 +752,15 @@ pub(crate) fn recv_from( } } +pub(crate) fn peek_sender(fd: Socket) -> io::Result<SockAddr> { + // Unix-like platforms simply truncate the returned data, so this implementation is trivial. + // However, for Windows this requires suppressing the `WSAEMSGSIZE` error, + // so that requires a different approach. + // NOTE: macOS does not populate `sockaddr` if you pass a zero-sized buffer. + let (_, sender) = recv_from(fd, &mut [MaybeUninit::uninit(); 8], MSG_PEEK)?; + Ok(sender) +} + #[cfg(not(target_os = "redox"))] pub(crate) fn recv_vectored( fd: Socket, @@ -866,6 +914,7 @@ fn into_timeval(duration: Option<Duration>) -> libc::timeval { } #[cfg(feature = "all")] +#[cfg(not(any(target_os = "haiku", target_os = "openbsd")))] pub(crate) fn keepalive_time(fd: Socket) -> io::Result<Duration> { unsafe { getsockopt::<c_int>(fd, IPPROTO_TCP, KEEPALIVE_TIME) @@ -875,7 +924,7 @@ pub(crate) fn keepalive_time(fd: Socket) -> io::Result<Duration> { #[allow(unused_variables)] pub(crate) fn set_tcp_keepalive(fd: Socket, keepalive: &TcpKeepalive) -> io::Result<()> { - #[cfg(not(any(target_os = "haiku", target_os = "openbsd")))] + #[cfg(not(any(target_os = "haiku", target_os = "openbsd", target_os = "nto")))] if let Some(time) = keepalive.time { let secs = into_secs(time); unsafe { setsockopt(fd, libc::IPPROTO_TCP, KEEPALIVE_TIME, secs)? } @@ -902,10 +951,16 @@ pub(crate) fn set_tcp_keepalive(fd: Socket, keepalive: &TcpKeepalive) -> io::Res } } + #[cfg(target_os = "nto")] + if let Some(time) = keepalive.time { + let secs = into_timeval(Some(time)); + unsafe { setsockopt(fd, libc::IPPROTO_TCP, KEEPALIVE_TIME, secs)? } + } + Ok(()) } -#[cfg(not(any(target_os = "haiku", target_os = "openbsd")))] +#[cfg(not(any(target_os = "haiku", target_os = "openbsd", target_os = "nto")))] fn into_secs(duration: Duration) -> c_int { min(duration.as_secs(), c_int::max_value() as u64) as c_int } @@ -993,6 +1048,33 @@ pub(crate) fn from_in6_addr(addr: in6_addr) -> Ipv6Addr { Ipv6Addr::from(addr.s6_addr) } +#[cfg(not(any( + target_os = "haiku", + target_os = "illumos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox", + target_os = "solaris", + target_os = "nto", +)))] +pub(crate) fn to_mreqn( + multiaddr: &Ipv4Addr, + interface: &crate::socket::InterfaceIndexOrAddress, +) -> libc::ip_mreqn { + match interface { + crate::socket::InterfaceIndexOrAddress::Index(interface) => libc::ip_mreqn { + imr_multiaddr: to_in_addr(multiaddr), + imr_address: to_in_addr(&Ipv4Addr::UNSPECIFIED), + imr_ifindex: *interface as _, + }, + crate::socket::InterfaceIndexOrAddress::Address(interface) => libc::ip_mreqn { + imr_multiaddr: to_in_addr(multiaddr), + imr_address: to_in_addr(interface), + imr_ifindex: 0, + }, + } +} + /// Unix only API. impl crate::Socket { /// Accept a new incoming connection from this listener. @@ -1276,6 +1358,162 @@ impl crate::Socket { } } + /// Get the value of the `TCP_CORK` option on this socket. + /// + /// For more information about this option, see [`set_cork`]. + /// + /// [`set_cork`]: Socket::set_cork + #[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 cork(&self) -> io::Result<bool> { + unsafe { + getsockopt::<Bool>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_CORK) + .map(|cork| cork != 0) + } + } + + /// Set the value of the `TCP_CORK` option on this socket. + /// + /// If set, don't send out partial frames. All queued partial frames are + /// sent when the option is cleared again. There is a 200 millisecond ceiling on + /// the time for which output is corked by `TCP_CORK`. If this ceiling is reached, + /// then queued data is automatically transmitted. + #[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 set_cork(&self, cork: bool) -> io::Result<()> { + unsafe { + setsockopt( + self.as_raw(), + libc::IPPROTO_TCP, + libc::TCP_CORK, + cork as c_int, + ) + } + } + + /// Get the value of the `TCP_QUICKACK` option on this socket. + /// + /// For more information about this option, see [`set_quickack`]. + /// + /// [`set_quickack`]: Socket::set_quickack + #[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 quickack(&self) -> io::Result<bool> { + unsafe { + getsockopt::<Bool>(self.as_raw(), libc::IPPROTO_TCP, libc::TCP_QUICKACK) + .map(|quickack| quickack != 0) + } + } + + /// Set the value of the `TCP_QUICKACK` option on this socket. + /// + /// If set, acks are sent immediately, rather than delayed if needed in accordance to normal + /// TCP operation. This flag is not permanent, it only enables a switch to or from quickack mode. + /// Subsequent operation of the TCP protocol will once again enter/leave quickack mode depending on + /// internal protocol processing and factors such as delayed ack timeouts occurring and data transfer. + #[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 set_quickack(&self, quickack: bool) -> io::Result<()> { + unsafe { + setsockopt( + self.as_raw(), + libc::IPPROTO_TCP, + libc::TCP_QUICKACK, + quickack as c_int, + ) + } + } + + /// Get the value of the `TCP_THIN_LINEAR_TIMEOUTS` option on this socket. + /// + /// For more information about this option, see [`set_thin_linear_timeouts`]. + /// + /// [`set_thin_linear_timeouts`]: Socket::set_thin_linear_timeouts + #[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 thin_linear_timeouts(&self) -> io::Result<bool> { + unsafe { + getsockopt::<Bool>( + self.as_raw(), + libc::IPPROTO_TCP, + libc::TCP_THIN_LINEAR_TIMEOUTS, + ) + .map(|timeouts| timeouts != 0) + } + } + + /// Set the value of the `TCP_THIN_LINEAR_TIMEOUTS` option on this socket. + /// + /// If set, the kernel will dynamically detect a thin-stream connection if there are less than four packets in flight. + /// With less than four packets in flight the normal TCP fast retransmission will not be effective. + /// The kernel will modify the retransmission to avoid the very high latencies that thin stream suffer because of exponential backoff. + #[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 set_thin_linear_timeouts(&self, timeouts: bool) -> io::Result<()> { + unsafe { + setsockopt( + self.as_raw(), + libc::IPPROTO_TCP, + libc::TCP_THIN_LINEAR_TIMEOUTS, + timeouts as c_int, + ) + } + } + /// Gets the value for the `SO_BINDTODEVICE` option on this socket. /// /// This value gets the socket binded device's interface name. @@ -1295,15 +1533,13 @@ impl crate::Socket { let mut buf: [MaybeUninit<u8>; libc::IFNAMSIZ] = unsafe { MaybeUninit::uninit().assume_init() }; let mut len = buf.len() as libc::socklen_t; - unsafe { - syscall!(getsockopt( - self.as_raw(), - libc::SOL_SOCKET, - libc::SO_BINDTODEVICE, - buf.as_mut_ptr().cast(), - &mut len, - ))?; - } + syscall!(getsockopt( + self.as_raw(), + libc::SOL_SOCKET, + libc::SO_BINDTODEVICE, + buf.as_mut_ptr().cast(), + &mut len, + ))?; if len == 0 { Ok(None) } else { @@ -1347,6 +1583,22 @@ impl crate::Socket { .map(|_| ()) } + /// Sets the value for the `SO_SETFIB` option on this socket. + /// + /// Bind socket to the specified forwarding table (VRF) on a FreeBSD. + #[cfg(all(feature = "all", any(target_os = "freebsd")))] + #[cfg_attr(docsrs, doc(cfg(all(feature = "all", any(target_os = "freebsd")))))] + pub fn set_fib(&self, fib: u32) -> io::Result<()> { + syscall!(setsockopt( + self.as_raw(), + libc::SOL_SOCKET, + libc::SO_SETFIB, + (&fib as *const u32).cast(), + mem::size_of::<u32>() as libc::socklen_t, + )) + .map(|_| ()) + } + /// Sets the value for `IP_BOUND_IF` option on this socket. /// /// If a socket is bound to an interface, only packets received from that @@ -1477,8 +1729,8 @@ impl crate::Socket { )] pub fn freebind(&self) -> io::Result<bool> { unsafe { - getsockopt::<c_int>(self.as_raw(), libc::SOL_SOCKET, libc::IP_FREEBIND) - .map(|reuse| reuse != 0) + getsockopt::<c_int>(self.as_raw(), libc::SOL_IP, libc::IP_FREEBIND) + .map(|freebind| freebind != 0) } } @@ -1500,13 +1752,78 @@ impl crate::Socket { any(target_os = "android", target_os = "fuchsia", target_os = "linux") ))) )] - pub fn set_freebind(&self, reuse: bool) -> io::Result<()> { + pub fn set_freebind(&self, freebind: bool) -> io::Result<()> { unsafe { setsockopt( self.as_raw(), - libc::SOL_SOCKET, + libc::SOL_IP, libc::IP_FREEBIND, - reuse as c_int, + freebind as c_int, + ) + } + } + + /// Get the value of the `IPV6_FREEBIND` option on this socket. + /// + /// This is an IPv6 counterpart of `IP_FREEBIND` socket option on + /// Android/Linux. For more information about this option, see + /// [`set_freebind`]. + /// + /// [`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<bool> { + unsafe { + getsockopt::<c_int>(self.as_raw(), libc::SOL_IPV6, libc::IPV6_FREEBIND) + .map(|freebind| freebind != 0) + } + } + + /// Set value for the `IPV6_FREEBIND` option on this socket. + /// + /// This is an IPv6 counterpart of `IP_FREEBIND` socket option on + /// Android/Linux. For more information about this option, see + /// [`set_freebind`]. + /// + /// [`set_freebind`]: crate::Socket::set_freebind + /// + /// # Examples + /// + /// On Linux: + /// + /// ``` + /// use socket2::{Domain, Socket, Type}; + /// use std::io::{self, Error, ErrorKind}; + /// + /// fn enable_freebind(socket: &Socket) -> io::Result<()> { + /// match socket.domain()? { + /// Domain::IPV4 => socket.set_freebind(true)?, + /// Domain::IPV6 => socket.set_freebind_ipv6(true)?, + /// _ => return Err(Error::new(ErrorKind::Other, "unsupported domain")), + /// }; + /// Ok(()) + /// } + /// + /// # fn main() -> io::Result<()> { + /// # let socket = Socket::new(Domain::IPV6, Type::STREAM, None)?; + /// # enable_freebind(&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( + self.as_raw(), + libc::SOL_IPV6, + libc::IPV6_FREEBIND, + freebind as c_int, ) } } @@ -1691,6 +2008,37 @@ impl crate::Socket { }) } } + + /// Attach Berkeley Packet Filter(BPF) on this socket. + /// + /// BPF allows a user-space program to attach a filter onto any socket + /// and allow or disallow certain types of data to come through the socket. + /// + /// For more information about this option, see [filter](https://www.kernel.org/doc/html/v5.12/networking/filter.html) + #[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))] + pub fn attach_filter(&self, filters: &[libc::sock_filter]) -> io::Result<()> { + let prog = libc::sock_fprog { + len: filters.len() as u16, + filter: filters.as_ptr() as *mut _, + }; + + unsafe { + setsockopt( + self.as_raw(), + libc::SOL_SOCKET, + libc::SO_ATTACH_FILTER, + prog, + ) + } + } + + /// Detach Berkeley Packet Filter(BPF) from this socket. + /// + /// For more information about this option, see [`attach_filter`] + #[cfg(all(feature = "all", any(target_os = "linux", target_os = "android")))] + pub fn detach_filter(&self) -> io::Result<()> { + unsafe { setsockopt(self.as_raw(), libc::SOL_SOCKET, libc::SO_DETACH_FILTER, 0) } + } } #[cfg_attr(docsrs, doc(cfg(unix)))] diff --git a/vendor/socket2/src/sys/windows.rs b/vendor/socket2/src/sys/windows.rs index cd28f97d9..0e36a1ccf 100644 --- a/vendor/socket2/src/sys/windows.rs +++ b/vendor/socket2/src/sys/windows.rs @@ -1,8 +1,8 @@ // Copyright 2015 The Rust Project Developers. // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. @@ -32,6 +32,7 @@ use winapi::um::winsock2::{ self as sock, u_long, POLLERR, POLLHUP, POLLRDNORM, POLLWRNORM, SD_BOTH, SD_RECEIVE, SD_SEND, WSAPOLLFD, }; +use winapi::um::winsock2::{SOCKET_ERROR, WSAEMSGSIZE, WSAESHUTDOWN}; use crate::{RecvFlags, SockAddr, TcpKeepalive, Type}; @@ -66,11 +67,14 @@ pub(crate) use winapi::shared::ws2def::{ IPPROTO_IP, SOL_SOCKET, SO_BROADCAST, SO_ERROR, SO_KEEPALIVE, SO_LINGER, SO_OOBINLINE, SO_RCVBUF, SO_RCVTIMEO, SO_REUSEADDR, SO_SNDBUF, SO_SNDTIMEO, SO_TYPE, TCP_NODELAY, }; +#[cfg(feature = "all")] +pub(crate) use winapi::shared::ws2ipdef::IP_HDRINCL; pub(crate) use winapi::shared::ws2ipdef::{ 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_DROP_MEMBERSHIP, IP_MREQ as IpMreq, IP_MULTICAST_IF, IP_MULTICAST_LOOP, IP_MULTICAST_TTL, - IP_TOS, IP_TTL, + 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_TOS, + IP_TTL, }; pub(crate) use winapi::um::winsock2::{linger, MSG_OOB, MSG_PEEK}; pub(crate) const IPPROTO_IPV6: c_int = winapi::shared::ws2def::IPPROTO_IPV6 as c_int; @@ -157,6 +161,10 @@ pub struct MaybeUninitSlice<'a> { _lifetime: PhantomData<&'a mut [MaybeUninit<u8>]>, } +unsafe impl<'a> Send for MaybeUninitSlice<'a> {} + +unsafe impl<'a> Sync for MaybeUninitSlice<'a> {} + impl<'a> MaybeUninitSlice<'a> { pub fn new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a> { assert!(buf.len() <= ULONG::MAX as usize); @@ -459,6 +467,38 @@ pub(crate) fn recv_from( } } +pub(crate) fn peek_sender(socket: Socket) -> io::Result<SockAddr> { + // Safety: `recvfrom` initialises the `SockAddr` for us. + let ((), sender) = unsafe { + SockAddr::init(|storage, addrlen| { + let res = syscall!( + recvfrom( + socket, + // Windows *appears* not to care if you pass a null pointer. + ptr::null_mut(), + 0, + MSG_PEEK, + storage.cast(), + addrlen, + ), + PartialEq::eq, + SOCKET_ERROR + ); + match res { + Ok(_n) => Ok(()), + Err(e) => match e.raw_os_error() { + Some(code) if code == (WSAESHUTDOWN as i32) || code == (WSAEMSGSIZE as i32) => { + Ok(()) + } + _ => Err(e), + }, + } + }) + }?; + + Ok(sender) +} + pub(crate) fn recv_from_vectored( socket: Socket, bufs: &mut [crate::MaybeUninitSlice<'_>], @@ -735,6 +775,32 @@ pub(crate) fn from_in6_addr(addr: in6_addr) -> Ipv6Addr { Ipv6Addr::from(*unsafe { addr.u.Byte() }) } +pub(crate) fn to_mreqn( + multiaddr: &Ipv4Addr, + interface: &crate::socket::InterfaceIndexOrAddress, +) -> IpMreq { + IpMreq { + imr_multiaddr: to_in_addr(multiaddr), + // Per https://docs.microsoft.com/en-us/windows/win32/api/ws2ipdef/ns-ws2ipdef-ip_mreq#members: + // + // imr_interface + // + // The local IPv4 address of the interface or the interface index on + // which the multicast group should be joined or dropped. This value is + // in network byte order. If this member specifies an IPv4 address of + // 0.0.0.0, the default IPv4 multicast interface is used. + // + // To use an interface index of 1 would be the same as an IP address of + // 0.0.0.1. + imr_interface: match interface { + crate::socket::InterfaceIndexOrAddress::Index(interface) => { + to_in_addr(&(*interface).into()) + } + crate::socket::InterfaceIndexOrAddress::Address(interface) => to_in_addr(interface), + }, + } +} + /// Windows only API. impl crate::Socket { /// Sets `HANDLE_FLAG_INHERIT` using `SetHandleInformation`. |